2011-06-17 48 views
2

考慮下面的查詢,並注意CALCULATE_INCENTIVE功能:有人可以幫我弄清Oracle的(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。

對我來說,CALCULATE_INCENTIVE函數在db中的每個員工上都被調用,而不是僅在前三個WHERE表達式返回的9條記錄上調用。我甚至試圖圍繞我想組合在一起進行短路評估的特定表達式進行括號試驗,但我無法弄清楚。

任何人有任何想法如何獲得CALCULATE_INCENTIVE 而不是評估如果任何以前的表達式返回false?

回答

2

一種方法是將主標準放入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; 
+0

有趣的是,你提出這個答案,因爲這是我在昨天剛問過的問題中給予我的解決方案,並且是我採取的最終路線。我知道Oracle支持短路評估,但我有興趣弄清楚它是如何實現的。 – oscilatingcretin

+0

@oscilatingcretin:那個解決方案在我心中是新鮮的,因爲我最近寫了它。對不起,我沒有意識到OP是一樣的。不過,這是唯一的(據我所知)迫使Oracle以特定的方式對評估進行短路。正如@Justin Cave指出的那樣,甲骨文將短路條件,但它基於優化器的路徑而不是查詢的語法。 – Allan

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)上有合成索引以及適當的統計數據,優化程序幾乎肯定會使用索引來評估前三個條件,然後僅針對遇到的ID調用CALCULATE_INCENTIVE函數另外三個標準。如果您在CALCULATE_INCENTIVE(id)上創建了基於函數的索引,則優化程序可能會使用該索引,而不是在運行時調用該函數。但是,如果優化器決定在每種情況下都更有效,那麼優化器可以完全自由地決定調用每一行的函數。

相關問題