2013-01-31 75 views
3

我正在創建一個多次使用2個嵌入式服務器函數的查詢。首先強制子查詢分辨率

問題:函數通過一個非常大的表進行搜索,並且它們需要很長時間才能執行。

目標:使用子查詢就好像它是一個表一樣,這樣我就可以在不運行函數的情況下引用列來多次生成列。

Example Pseudocode:

Select general.column1, general.column2, general.column1-general.column2 
from (select package.function1('I take a long time') column1, 
     package.function2('I take even longer') column2, 
     normal_column 
     from bigtable) general; 

當我運行我的代碼general.column1將引用函數列1的聲明,而不是由它返回(這是最終我後)的數據。

我對SQL相當陌生,所以任何幫助表示讚賞,如果您需要更多信息,我會盡我所能提供它。

謝謝!

回答

4

我建議你使用子查詢保理。第一個子查詢將只執行一次,然後用於查詢的其餘部分。

WITH function_result AS 
    (SELECT package.function1('I take a long time') column1 
    ,  package.function2('I take even longer') column2 
    FROM dual) 
SELECT function_result.column1 
,  function_result.column2 
,  function_result.column1 - function_result.column2 
,  bigtable.normal_column 
FROM bigtable 
+0

謝謝,這正是我正在尋找的,並加快了我的SQL大約1/2的時間。 – Rolan

4

一般來說,你想要做的是在這種情況下是採取標量子查詢緩存advatage。

即認沽:

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; 

delcaring的功能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次(每行一次)。現在讓我們使用標量緩存:

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 

178調用而不是57k! 在你的案例中,你只顯示了你有一個字面值和每行不變的輸入(如果是這種情況,使用標量緩存後的調用次數應該是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在11g中,我們有result_cache,我們可以到位的確定性,對subsequant運行到0調用,將減少電話。

+0

我試過使用這種方法,但執行時間相當於運行我的查詢。我猜測我還沒有完全明白你在做什麼。這就是說,我有一些新的詞彙和技術來查找。謝謝! – Rolan