Ответ 1
Если вы это сделаете:
select t.x, t.y, (select my_function(t.x) from dual)
from t
тогда Oracle может использовать кэширование подзапросов для достижения сокращенных вызовов функций.
В операторе SQL SELECT
я хотел бы выполнить функцию, которая является детерминированной для области действия этого оператора SELECT
(или транзакция тоже будет в порядке):
select t.x, t.y, my_function(t.x) from t
Многие значения t.x
совпадают, поэтому Oracle может снова и снова опускать одну и ту же функцию, чтобы ускорить работу. Но если я обозначу функцию как DETERMINISTIC
, результаты могут быть кэшированы между несколькими версиями этого запроса. Причина, по которой я не могу использовать DETERMINISTIC
, состоит в том, что my_function
использует параметр конфигурации, который время от времени изменяется.
Можно ли использовать другое ключевое слово? Есть ли уловы, о которых я должен знать (проблемы с памятью, concurrency и т.д.)? Или, может быть, любые другие трюки, такие как аналитические функции для вызова функции только один раз за значение t.x
(без значительного воздействия на производительность)?
Если вы это сделаете:
select t.x, t.y, (select my_function(t.x) from dual)
from t
тогда Oracle может использовать кэширование подзапросов для достижения сокращенных вызовов функций.
Это не ответ на ваш вопрос, но может быть для вас решением.
Этот параметр конфигурации, который вы упомянули, не может быть добавлен в качестве параметра для работы?
В этом случае my_function(t.x, val1)
- это другое дело vs my_function(t.x, val2)
.
Возможным упрощенным обходным путем было бы создать вторую, DETERMINISTIC функцию, которая вызывает первую; но вторая функция принимает дополнительный, бессмысленный параметр, для которого вы предоставляете другое литеральное значение в каждом запросе, который использует эту функцию.
Другой метод - поместить функцию в пакет и установить результат как глобальную переменную. Затем, когда вы вызываете функцию, проверьте, являются ли входные переменные такими же, как и раньше, и быстро возвращают глобальную переменную, если это так:
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>