Oracle :Выбрать сразу после вставки в сериализуемую транзакцию

В последнее время я столкнулся со странной проблемой, программируя в базе данных Oracle :внутри сериализуемой транзакции, я делаю массовую вставку (INSERT... SELECT ), и сразу после этого я открываю курсор с помощью SELECT на измененном столе. Я предполагал, что этот курсор будет включать только что вставленные строки, но, к моему удивлению, его содержимое ошибочно, иногда включая все вновь вставленные строки, а иногда только подмножество.

Я решил эту проблему, зафиксировав перед открытием курсора, но поведение меня озадачило. Можно ли на самом деле доверять выбору после вставки внутри той же транзакции без промежуточной фиксации? Или это поведение как-то связано с сериализуемостью транзакции?

Последующие действия:При попытке создать воспроизводимый тестовый пример я смог получить такое поведение только после того, как добавил индекс (, в данном случае индекс первичного ключа, в реальном коде это был обычный индекс ). Возможно, проблема заключается во времени, затраченном на построение индекса, так что SELECT фактически использует неполный индекс для получения результатов? В любом случае, вот воспроизводимый тестовый пример:

-- 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;

В этом примере я ожидал бы, что TEST _CASE _2 также будет иметь 100 000 строк. Воспроизведя этот тестовый пример (в загруженной -свободной базе данных ), я получил около 400 -500 вставленных строк. Удалив оператор, устанавливающий транзакцию как сериализуемую, я получил правильное количество строк в 100 000.

7
задан user1578874 7 August 2012 в 10:28
поделиться