2

次のクエリを検討し、CALCULATE_INCENTIVE 関数に注目してください。

SELECT EMP.* FROM EMPLOYEES EMPS
WHERE
    EMP.STATUS = 1 AND
    EMP.HIRE_DATE > TO_DATE('1/1/2010') AND
    EMP.FIRST_NAME = 'JOHN' AND
    CALCULATE_INCENTIVE(EMP.ID) > 1000
ORDER BY EMPS.ID DESC;

私は、Oracle が .NET が and/or ロジックで使用するのと同じ (または同様の) 短絡回路を使用しているという印象を受けました。たとえば、EMP.STATUS = 2 の場合、式全体がとにかく false を返すため、残りの式を評価する必要はありません。

私の場合、CALCULATE_INCENTIVE 関数は、最初の 3 つの WHERE 式が返す 9 つのレコードだけではなく、データベース内のすべての従業員に対して呼び出されています。短絡評価のためにグループ化したい特定の式を括弧で囲んでみましたが、わかりません。

前の式のいずれかが false を返した場合にCALCULATE_INCENTIVEを評価しないようにする方法はありますか?

4

2 に答える 2

2

1 つの方法は、Oracle が最適化して取り除くことができないサブクエリにプライマリ基準を配置し、次に外側のクエリにセカンダリ基準を配置することです。Oracle がサブクエリを最適化しないようにする最も簡単な方法は、select ステートメントに rownum を含めることです。

SELECT * FROM (
   SELECT EMP.*, ROWNUM 
   FROM EMPLOYEES EMPS
   WHERE
       EMP.STATUS = 1
       AND EMP.HIRE_DATE > TO_DATE('1/1/2010')
       AND EMP.FIRST_NAME = 'JOHN')
WHERE CALCULATE_INCENTIVE(ID) > 1000
ORDER BY EMPS.ID DESC;
于 2011-06-17T12:44:09.197 に答える
1

Oracle は、PL/SQL での短絡評価をサポートしています。ただし、SQL では、オプティマイザーは自由に述語を任意の順序で評価したり、述語をビューやサブクエリにプッシュしたり、SQL ステートメントを必要に応じて変換したりできます。これは、述語が特定の順序で適用されることに依存してはならないことを意味し、順序述語が WHERE 句に現れるのは本質的に無関係になります。使用可能なインデックス、存在するオプティマイザ統計、オプティマイザ パラメータ、およびシステム統計はすべて、WHERE 句の述語の順序よりもはるかに重要です。

たとえば、PL/SQL では、実際に呼び出された場合にエラーをスローする関数を使用して、これを実証できます。

SQL> ed
Wrote file afiedt.buf

  1  create function throw_error( p_parameter IN NUMBER )
  2    return number
  3  as
  4  begin
  5    raise_application_error( -20001, 'The function was called' );
  6    return 1;
  7* end;
SQL> /

Function created.

SQL> ed
Wrote file afiedt.buf

  1  declare
  2    l_num NUMBER;
  3  begin
  4    l_num := 1;
  5    if( l_num = 2 and throw_error( l_num ) = 2 )
  6    then
  7      null;
  8    else
  9      dbms_output.put_line( 'Short-circuited the AND' );
 10    end if;
 11    if( l_num = 1 or throw_error( l_num ) = 2 )
 12    then
 13      dbms_output.put_line( 'Short-circuited the OR' );
 14    end if;
 15* end;
 16  /
Short-circuited the AND
Short-circuited the OR

PL/SQL procedure successfully completed.

一方、SQL では、操作の順序はユーザーではなくオプティマイザーによって決定されるため、オプティマイザーは自由に短絡することも短絡しないこともできます。Jonathan Gennick は Subquery Madness というすばらしい記事を書いています。これについて詳しく説明しています。あなたの特定のケースでは、(FIRST_NAME, HIRE_DATE, STATUS) に適切な統計とともに複合インデックスがある場合、オプティマイザーはほぼ確実にインデックスを使用して最初の 3 つの条件を評価し、次に一致CALCULATE_INCENTIVEした ID の関数のみを呼び出します。他の3つの基準。関数ベースのインデックスを作成した場合CALCULATE_INCENTIVE(id)、オプティマイザーは、実行時に関数をまったく呼び出すのではなく、それを使用する可能性があります。ただし、オプティマイザは、どちらの場合でも、その方が効率的であると判断した場合、すべての行に対して関数を呼び出すことを完全に自由に決定できます。

于 2011-06-17T14:57:12.043 に答える