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

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

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

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

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

Ответ 1

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

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

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

Ответ 2

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

Ответ 3

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

Ответ 4

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

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>