Ostatnio natknąłem się na dziwny problem, programując w bazie danych Oracle: wewnątrz transakcji serializowalnej, robię masową wstawkę (INSERT ... SELECT), a zaraz potem, otwórz kursor za pomocą przycisku SELECT na zmienionej tablicy. Zakładałem, że kursor ten będzie zawierał nowo wstawione wiersze, ale ku mojemu zaskoczeniu jego zawartość jest nieregularna, czasami zawiera wszystkie nowo wstawione wiersze, a czasem tylko podzbiór.Oracle: Wybierz natychmiast po wstawieniu do transakcji szeregowalnej
Rozwiązałem ten problem, zatwierdzając przed otwarciem kursora, ale zachowanie mnie zaintrygowało. Czy wybór po wstawieniu w ramach tej samej transakcji, bez zatwierdzenia interwiningu, może być zaufany? Czy to zachowanie jest w jakiś sposób związane z serializacją transakcji?
Followup: Gdy próbuje stworzyć powtarzalne przypadek testowy, byłem tylko w stanie uzyskać ten problem raz dodałem indeksu (w tym przypadku indeks klucza podstawowego, od rzeczywistego kodu to był regularny index). Być może problem leży w czasie poświęconym na budowanie indeksu, tak aby SELECT używał niekompletnego indeksu do pobierania wyników? W każdym razie, tu idzie powtarzalnej przypadek testowy:
-- Create empty source table
CREATE TABLE TEST_CASE_1 AS
(SELECT 'CONTENT' AS CONTENT
FROM DUAL
WHERE 1 = 2)
-- Add primary key
ALTER TABLE TEST_CASE_1
ADD CONSTRAINT TEST_CASE_1_PK PRIMARY KEY (CONTENT);
-- Create empty destination table
CREATE TABLE TEST_CASE_2 AS
(SELECT 'CONTENT' AS CONTENT
FROM DUAL
WHERE 1 = 2)
-- Example of faulty code
BEGIN
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
-- Populate with 100.000 rows (I used ALL_OBJECTS but any source of 100.000 rows is good)
INSERT INTO TEST_CASE_1
(SELECT ROWNUM
FROM ALL_OBJECTS
WHERE ROWNUM <= 100000);
INSERT INTO TEST_CASE_2
(SELECT *
FROM TEST_CASE_1
WHERE CONTENT > 0);
COMMIT;
END;
W tym przykładzie, spodziewałbym TEST_CASE_2 również mieć 100.000 wierszy. Reprodukując ten przypadek testowy (w bez obciążeniowej bazie danych), uzyskałem około 400-500 wstawionych wierszy. Usuwając instrukcję ustawiającą transakcję jako możliwą do serializacji, uzyskałem poprawną liczbę wierszy 100 000.
Czy otwierasz kursor w tej samej sesji bazy danych co podczas wstawiania? Gdzie robisz tę pracę - w rzeczywistości w bazie danych lub z aplikacji klienckiej - i czy ta ostatnia posiada pulę połączeń, a Ty (czasami) uzyskujesz inne połączenie dla tych dwóch działań? –
Kursor jest otwierany w tej samej sesji. Pierwotnie kursor został otwarty w bazie danych, a następnie iterowany w pliku wykonywalnym .NET, ale w celu wyizolowania problemu wykonałem wersję procedury, która iterowała kursor wewnątrz bazy danych, a problem utrzymywał się - w rzeczywistości przed wykonaniem tego nie mogłem ". t przekonaj się, że problem dotyczył wyboru po wstawieniu. – user1578874
To nie powinno się zdarzyć; from [the docs] (http://docs.oracle.com/cd/E11882_01/server.112/e25789/consist.htm#sthref1189) "Na poziomie izolacji serializacji, transakcja widzi tylko zmiany popełnione w momencie transakcji -nie zapytanie rozpoczęte i zmiany dokonane przez samą transakcję, więc powinieneś zobaczyć własne zmiany. Może to być błąd w twojej konkretnej wersji. Zaangażowanie sprawia, że zmiana poziomu izolacji jest bezsensowna. Czy możesz opublikować powtarzalny test testowy? –