4

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 は、それによって返されるデータではなく、column1 のステートメント内の関数を参照します (これが最終的に求めているものです)。

私は SQL にかなり慣れていないので、どんな助けでも大歓迎です。さらに情報が必要な場合は、最善を尽くして提供します。

ありがとう!

4

2 に答える 2

5

サブクエリファクタリングを使用することをお勧めします。最初のサブクエリは1回だけ実行され、残りのクエリで使用されます。

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
于 2013-02-01T08:35:00.680 に答える
4

一般に、この場合にやりたいことは、スカラーサブクエリキャッシングを利用することです。

つまり、次のようになります。

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 呼び出しに減少します。

于 2013-01-31T21:13:36.393 に答える