Существует ли прагма PL / SQL, аналогичная DETERMINISTIC, но для области действия одного SELECT SQL? - PullRequest
10 голосов
/ 01 сентября 2011

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

select t.x, t.y, my_function(t.x) from t

Многие значения t.x одинаковы, поэтому Oracle может пропустить вызов одной и той же функции снова и снова, чтобы ускорить процесс. Но если я маркирую функцию как DETERMINISTIC, результаты могут быть кэшированы между несколькими выполнениями этого запроса. Причина, по которой я не могу использовать DETERMINISTIC, заключается в том, что my_function использует параметр конфигурации, который время от времени изменяется.

Могу ли я использовать другое ключевое слово? Есть ли какие-то уловки, о которых мне следует знать (проблемы с памятью, параллелизм и т. Д.)? Или, может быть, есть какие-то другие приемы, такие как аналитические функции, для вызова функции только один раз за t.x значение (без существенного влияния на производительность)?

Ответы [ 4 ]

11 голосов
/ 01 сентября 2011

Если вы сделаете это:

select t.x, t.y, (select my_function(t.x) from dual)
from t

тогда Oracle может использовать кэширование подзапросов для сокращения вызовов функций.

3 голосов
/ 01 сентября 2011

Это не ответ на ваш вопрос, но может быть решением для вас. Этот параметр конфигурации, который вы упомянули, не может быть добавлен в качестве параметра для функции? В этом случае my_function(t.x, val1) - это другое, чем my_function(t.x, val2).

2 голосов
/ 01 сентября 2011

Другой метод - поместить функцию в пакет и установить результат как глобальную переменную.Затем при вызове функции проверьте, совпадают ли входные переменные с прежними, и быстро верните глобальную переменную, если это так:

SQL> create or replace package temp is
  2
  3    function blah ( PIndex integer ) return integer;
  4
  5  end temp;
  6  /

Package created.

SQL>
SQL> create or replace package body temp is
  2
  3    GResult integer := 0;
  4    GIndex integer;
  5
  6    function blah ( PIndex integer ) return integer is
  7
  8      begin
  9
 10        if Gindex = Pindex then
 11          return Gresult;
 12        else
 13          GIndex := Pindex;
 14          GResult := Pindex;
 15        end if;
 16
 17        return Gresult;
 18
 19      end blah;
 20
 21  end temp;
 22  /

Package body created.

SQL>
SQL> select temp.blah(1) from dual;

TEMP.BLAH(1)
------------
           1

SQL>
SQL> select temp.blah(1) from dual;

TEMP.BLAH(1)
------------
           1

SQL>
SQL> select temp.blah(2) from dual;

TEMP.BLAH(2)
------------
           2

SQL>
2 голосов
/ 01 сентября 2011

Возможный упрощенный обходной путь - создать вторую ДЕТЕРМИНИСТИЧЕСКУЮ функцию, которая вызывает первую; но пусть вторая функция принимает дополнительный, бессмысленный параметр, для которого вы предоставляете различное литеральное значение в каждом запросе, который использует функцию.

...