функция pl / sql вызывается сколько раз? - PullRequest
8 голосов
/ 21 июля 2011

Предположим, у вас есть следующее обновление:

Update table set col1 = func(col2)
where col1<>func(col2)

Функция func оценивается два раза для каждой строки или один раз для каждой строки?

Спасибо

Ответы [ 3 ]

11 голосов
/ 21 июля 2011

Это такая ситуация, когда некоторые эксперименты полезны (это было проведено на 10g). Используя следующий запрос, мы можем сказать, что обычные функции, использующие одни и те же параметры (в данном случае ни одного), будут выполняться при каждом вызове:

select dbms_random.value() from all_tables

Это связано с тем, что Oracle предполагает, что функция не будет возвращать одно и то же значение последовательно, если вы не укажете обратное. Мы можем сделать это, создав функцию с помощью ключевого слова deterministic:

CREATE FUNCTION rand_det
   RETURN NUMBER
   DETERMINISTIC AS
BEGIN
   RETURN DBMS_RANDOM.VALUE ();
END;

Использование этой функции вместо dbms_random в первом запросе говорит нам, что запрос выполняется только один раз, несмотря на множество вызовов. Но это только проясняет раздел select. Что, если мы используем одну и ту же детерминированную функцию в выражении select и where. Мы можем проверить это, используя следующий запрос:

SELECT rand_det
FROM   all_tables
WHERE  rand_det > .5;

Возможно, вам придется выполнить это несколько раз, чтобы увидеть наше доказательство, но, в конце концов, вы увидите список значений менее 0,5. Это дает нам свидетельство того, что даже детерминированная функция выполняется дважды: один раз для каждого раздела, в котором она появляется. В качестве альтернативы вы можете изменить нашу детерминированную функцию следующим образом, а затем выполнить следующий запрос, который покажет 2 строки, записанные в DBMS_OUTPUT.

CREATE OR REPLACE FUNCTION rand_det
   RETURN NUMBER
   DETERMINISTIC AS
BEGIN
   DBMS_OUTPUT.put_line ('Called!');
   RETURN DBMS_RANDOM.VALUE ();
END;

SELECT rand_det
FROM   all_tables;
10 голосов
/ 21 июля 2011

Хотя мне нравится ответ Аллана за то, что он показывает, как это исследовать, я думаю, что реальный урок, который нужно извлечь, заключается в том, что вы не должны полагаться на ответ на этот вопрос, если можете его избежать.

Вот полезный пост на тему от Тома Кайта («Я писал тысячи раз, что вы не можете полагаться на то, сколько раз, когда или если SQL будет вызывать вашу функцию».) Еще до 11g введения результатаВ кеше нет никаких гарантий относительно того, сколько раз будет вызвана функция при обработке оператора SQL.Это может зависеть от плана выполнения, который может меняться со временем.

Если вас беспокоит производительность, а ваша функция - детерминистическая, кеша результатов 11g, вероятно, достаточно - это не гарантирует конкретного ограничения наколичество вызовов к функции, но должно значительно сократить количество избыточных вызовов.(См. Ссылку в ответе @cularis.)

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

2 голосов
/ 21 июля 2011

Для 11g он будет вызываться один раз для каждого нового вхождения col2. Для следующих вызовов используется кэшированный результат, если caching включен.

...