2011-06-17 5 views
2

は、次の問合せを検討し、CALCULATE_INCENTIVE機能に気づく:誰かがオラクルの(10g)AND/ORショート回路を理解する手助けができますか?

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はそのおよび/またはロジックで使用するのと同じ(または類似の)ショート回路を使用するという印象の下にあったが。たとえば、EMP.STATUS = 2の場合、式全体がfalseを返すため、残りの式を評価する必要はありません。

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

CALCULATE_INCENTIVE を入手する方法はありますか?前述の式のいずれかがfalseを返す場合、は評価されません。

答えて

2

1つの方法は、Oracleが最適化できないサブクエリに1次条件を設定し、2次条件を外部クエリに配置することです。

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; 
+0

これは私がちょうど昨日尋ねた質問で私に与えられた解決策であり、私が取った究極のルートであるので、あなたはこの答えを提案して興味深い。私はオラクル社が短絡評価をサポートしていることを知っています。それがどのように機能するかを理解することに興味があります。 – oscilatingcretin

+0

@ oscillatingcretin:私が最近書いたので、そのソリューションは私の心の中で新鮮でした。申し訳ありませんが、私はOPが同じであることを認識しませんでした。それでも、これはオラクルに特定の方法で評価を短絡させる唯一の方法です。 @Justin Caveが指摘するように、Oracleは回路状態を短絡しますが、問合せの構文ではなく、オプティマイザのパスに基づいています。 – Allan

1

OracleはPL/SQLで短絡評価をサポートしています。Oracleは副問合せを最適化しないことを保証する最も簡単な方法は、select文でROWNUMを含めることです。ただし、SQLでは、オプティマイザは任意の順序で述語を評価し、述語をビューおよびサブクエリにプッシュし、それ以外の場合はSQL文を適切に変換します。これは、特定の順序で適用される述語に頼るべきではなく、WHERE句に表示される順序述語を本質的に無関係にすることを意味します。使用可能な索引、存在するオプティマイザー統計、オプティマイザー・パラメーター、およびシステム統計は、WHERE節の述部の順序よりもはるかに重要です。

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

は、一方では、動作の順序はありませんあなたによって、オプティマイザによって決定されるので、オプティマイザは、短絡または短絡させないが、それは望んでいるに無料です。 Jonathan Gennickには、これについてある程度詳しく説明した素晴らしい記事Subquery Madness!があります。特定のケースでは、(FIRST_NAME、HIRE_DATE、STATUS)のコンポジット・インデックスが適切な統計情報と共に表示されている場合、オプティマイザはほとんどの場合、最初の3つの条件を評価するためにインデックスを使用して、それに対応するIDに対してCALCULATE_INCENTIVE関数他の3つの基準。ファンクション索引をCALCULATE_INCENTIVE(id)に作成した場合、オプティマイザは実行時にファンクションをコールするのではなく、そのファンクションを使用します。しかし、オプティマイザは、どちらの場合でも、それがより効率的であると判断した場合には、すべての行に対して関数を呼び出すことを完全に自由にすることができます。

関連する問題