質問

次のように、Oracleの select または where 句で関数呼び出しがあるとします:

select a, b, c, dbms_crypto.hash(utl_raw.cast_to_raw('HELLO'),3)
  from my_table

同様の例をMS SQLServerに構築できます。

それぞれの場合に予想される動作は何ですか?

HASH 関数はテーブル内の各行に対して1回呼び出されますか、それとも定数パラメーターを持ち、副作用

どうもありがとう。

役に立ちましたか?

解決

Oracleの答えは、依存することです。この関数は、「決定的」とマークされていない限り、選択されたすべての行に対して呼び出されます。その場合、関数は一度だけ呼び出されます。

CREATE OR REPLACE PACKAGE TestCallCount AS
    FUNCTION StringLen(SrcStr VARCHAR) RETURN INTEGER;
    FUNCTION StringLen2(SrcStr VARCHAR) RETURN INTEGER DETERMINISTIC;
    FUNCTION GetCallCount RETURN INTEGER;
    FUNCTION GetCallCount2 RETURN INTEGER;
END TestCallCount;

CREATE OR REPLACE PACKAGE BODY TestCallCount AS
    TotalFunctionCalls INTEGER := 0;
    TotalFunctionCalls2 INTEGER := 0;

    FUNCTION StringLen(SrcStr VARCHAR) RETURN INTEGER AS
    BEGIN
        TotalFunctionCalls := TotalFunctionCalls + 1;
        RETURN Length(SrcStr);
    END;
    FUNCTION GetCallCount RETURN INTEGER AS
    BEGIN
        RETURN TotalFunctionCalls;
    END;

    FUNCTION StringLen2(SrcStr VARCHAR) RETURN INTEGER DETERMINISTIC AS
    BEGIN
        TotalFunctionCalls2 := TotalFunctionCalls2 + 1;
        RETURN Length(SrcStr);
    END;
    FUNCTION GetCallCount2 RETURN INTEGER AS
    BEGIN
        RETURN TotalFunctionCalls2;
    END;

END TestCallCount;




SELECT a,TestCallCount.StringLen('foo') FROM(
    SELECT 0 as a FROM dual
    UNION
    SELECT 1 as a FROM dual
    UNION
    SELECT 2 as a FROM dual
);

SELECT TestCallCount.GetCallCount() AS TotalFunctionCalls FROM dual;

出力:

A                      TESTCALLCOUNT.STRINGLEN('FOO') 
---------------------- ------------------------------ 
0                      3                              
1                      3                              
2                      3                              

3 rows selected


TOTALFUNCTIONCALLS     
---------------------- 
3                      

1 rows selected

したがって、最初のケースではStringLen()関数が3回呼び出されました。決定論的に示されるStringLen2()で実行する場合:

SELECT a,TestCallCount.StringLen2('foo') from(
    select 0 as a from dual
    union
    select 1 as a from dual
    union
    select 2 as a from dual
);

SELECT TestCallCount.GetCallCount2() AS TotalFunctionCalls FROM dual;

結果:

A                      TESTCALLCOUNT.STRINGLEN2('FOO') 
---------------------- ------------------------------- 
0                      3                               
1                      3                               
2                      3                               

3 rows selected

TOTALFUNCTIONCALLS     
---------------------- 
1                      

1 rows selected

したがって、StringLen2()関数は、確定的とマークされているため、一度だけ呼び出されました。

決定的とマークされていない関数については、クエリを次のように変更することでこれを回避できます。

select a, b, c, hashed
  from my_table
cross join (
  select dbms_crypto.hash(utl_raw.cast_to_raw('HELLO'),3) as hashed from dual
);

他のヒント

SQLサーバーの場合、1行ごとに評価されます。

関数を1回実行し、変数に割り当てて、クエリで変数を使用することで、大幅に改善されます。

短い答え....それは依存します。

関数がデータにアクセスしている場合、ORACLEは各行で同じになるかどうかを知らないため、それぞれに対してクエリを実行する必要があります。たとえば、関数が常に同じ値を返す単なるフォーマッターである場合は、キャッシュを有効にして(確定的としてマークする)、関数呼び出しを1回だけ行うことができます。

調査したいのは、ORACLE WITHサブクエリです:

  

WITH query_name句を使用すると、   サブクエリブロックに名前を割り当てます。君は   その後、サブクエリブロックを参照できます   クエリ内の複数の場所   クエリ名を指定します。オラクル   を処理してクエリを最適化します   インラインビューとしてのクエリ名または   一時テーブルとして

こちらから引用テキストを入手しました。これには多くの例があります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top