一般に、この場合にやりたいことは、スカラーサブクエリキャッシングを利用することです。
つまり、次のようになります。
Select general.column1, general.column2, general.column1-general.column2
from (select (select package.function1('I take a long time') from dual) column1,
(select package.function2('I take even longer') from dual) column2,
normal_column
from bigtable) general;
関数を宣言するdeterministic
ことも、決定論的である場合に役立ちます。
小さな例:
SQL> create or replace function testfunc(i varchar2)
2 return varchar2
3 is
4 begin
5 dbms_application_info.set_client_info(userenv('client_info')+1 );
6 return 'hi';
7 end;
8 /
Function created.
あなたが持っているように、関数への呼び出しをテストしましょう:
SQL> exec dbms_application_info.set_client_info(0);
PL/SQL procedure successfully completed.
SQL> set autotrace traceonly
SQL> select *
2 from (select testfunc(owner) a
3 from all_objects);
57954 rows selected.
SQL> select userenv('client_info') from dual;
USERENV('CLIENT_INFO')
----------------------------------------------------------------
57954
関数は 57954 回 (行ごとに 1 回) 呼び出されました。スカラーキャッシングを使用しましょう:
SQL> exec dbms_application_info.set_client_info(0);
PL/SQL procedure successfully completed.
SQL> select *
2 from (select (select testfunc(owner) from dual) a
3 from all_objects);
57954 rows selected.
SQL> select userenv('client_info') from dual;
USERENV('CLIENT_INFO')
----------------------------------------------------------------
178
57k の代わりに 178 コール! あなたの場合、リテラルがあり、行ごとに変化する入力がないことを示しただけです(この場合、スカラーキャッシュを使用した後の呼び出しの数は1になるはずです)。
決定論を追加すると、次のようになります。
SQL> create or replace function testfunc(i varchar2)
2 return varchar2 deterministic
3 is
4 begin
5 dbms_application_info.set_client_info(userenv('client_info')+1 );
6 return 'hi';
7 end;
8 /
Function created.
SQL> exec dbms_application_info.set_client_info(0);
PL/SQL procedure successfully completed.
SQL> select *
2 from (select (select testfunc(owner) from dual) a
3 from all_objects);
57954 rows selected.
SQL> select userenv('client_info') from dual;
USERENV('CLIENT_INFO')
----------------------------------------------------------------
55
現在は 55 までresult_cache
減少しています。11g では、決定論的の代わりに配置できるものがあります。これにより、サブセカント実行の呼び出しが 0 呼び出しに減少します。