Таблица мутаций в Oracle 11, вызванная функцией - PullRequest
13 голосов
/ 30 марта 2012

Мы недавно обновили Oracle 10 до Oracle 11.2.После обновления я начал видеть ошибку изменяющейся таблицы, вызванную функцией, а не триггером (с которым я никогда раньше не сталкивался).Это старый код, который работал в предыдущих версиях Oracle.

Вот сценарий, который вызовет ошибку:

create table mutate (
    x NUMBER,
    y NUMBER
);

insert into mutate (x, y)
values (1,2);

insert into mutate (x, y)
values (3,4);

Я создал две строки.Теперь я удвою свои строки, вызвав этот оператор:

insert into mutate (x, y)
select x + 1, y + 1 
from mutate;

Это не обязательно, чтобы дублировать ошибку, но это поможет с моей демонстрацией позже.Таким образом, содержимое таблицы теперь выглядит так:

X,Y
1,2
3,4
2,3
4,5

Все хорошо.Теперь для забавной части:

create or replace function mutate_count
return PLS_INTEGER
is
    v_dummy PLS_INTEGER;
begin
    select count(*) 
    into v_dummy
    from mutate;

    return v_dummy;
end mutate_count;
/

Я создал функцию для запроса моей таблицы и возврата счетчика.Теперь я объединю это с оператором INSERT:

insert into mutate (x, y)
select x + 2, y + 2
from mutate
where mutate_count() = 4;

Результат?Эта ошибка:

ORA-04091: table MUTATE is mutating, trigger/function may not see it
ORA-06512: at "MUTATE_COUNT", line 6

Итак, я знаю, что вызывает ошибку, но мне любопытно, почему почему .Разве Oracle не выполняет SELECT, получает набор результатов и , а затем выполняет массовую вставку этих результатов?Я ожидал бы только ошибку изменяющейся таблицы, если записи уже были вставлены до завершения запроса.Но если бы Oracle это сделал, разве более раннее утверждение:

insert into mutate (x, y)
select x + 1, y + 1 
from mutate;

не запустило бы бесконечный цикл?

ОБНОВЛЕНИЕ:

По ссылке Джеффри я нашел это в Oracle docs :

По умолчанию Oracle гарантирует согласованность чтения на уровне инструкций.Набор данных, возвращаемых одним запросом, согласуется с одним моментом времени.

Есть также комментарий автора в его посте :

Можно спорить, почему Oracle не обеспечивает эту «согласованность чтения на уровне инструкций» для повторных вызовов функций, которые появляются внутри инструкций SQL.Насколько я могу судить, это можно считать ошибкой.Но в настоящее время это так.

Правильно ли я считаю, что это поведение изменилось между версиями Oracle 10 и 11?

Ответы [ 2 ]

9 голосов
/ 30 марта 2012

Прежде всего,

insert into mutate (x, y)
select x + 1, y + 1 
from mutate;

Не запускает бесконечный цикл, поскольку запрос не увидит вставленные данные - только данные, которые существовали на момент начала оператора. Новые строки будут видны только для последующих операторов.

Это объясняет это довольно хорошо:

Когда Oracle выходит из SQL-движка, который в данный момент выполняет обновить оператор и вызывает функцию, то эта функция - просто как триггер обновления после строки - видит промежуточные состояния EMP, поскольку они существуют во время выполнения оператора обновления. это подразумевает, что возвращаемое значение наших вызовов функций сильно зависит от порядка обновления строк.

8 голосов
/ 30 марта 2012

Согласованность чтения на уровне выписки и согласования чтения на уровне транзакции ".

Из руководства:

"Если список SELECT содержит функцию, то база данных применяется Согласованность чтения на уровне операторов на уровне операторов для запуска SQL в коде функции PL / SQL , , а не в родительском SQL уровень . Например, функция может получить доступ к таблице, данные которой изменено и передано другим пользователем. Для каждого выполнения ВЫБЕРИТЕ в функции новый снимок установлено ".

Обе концепции объясняются в «Концепциях базы данных Oracle®»:

http://download.oracle.com/docs/cd/B19306_01/server.102/b14220/consist.htm#sthref1955


- >>> ОБНОВЛЕНИЕ

- >>> * Раздел добавлен после OP был закрыт

Правило

Техническое правило, хорошо связанное г-ном Кемпом (@ jeffrey-kemp) и хорошо объясненное Тооном Коппелаарсом здесь , сообщается в "Pl / Справочник по языку SQL - Контроль побочных эффектов подпрограмм PL / SQL"(ваша функция нарушает RNDS не читает состояние базы данных):

При вызове из оператора INSERT, UPDATE или DELETE функция не может запрашивать или изменять какие-либо таблицы базы данных, измененные этим оператором.

Если функция запрашивает или изменяет таблицу и оператор DML в этой таблице вызывается функция, затем ORA-04091 (таблица мутаций ошибка)

Функции PL / SQL, которые могут вызывать операторы SQL

...