2010-05-07 67 views
3

我有一個使用EXECUTE IMMEDIATE調用的存儲過程。我面臨的問題是,當我直接調用過程時,解釋計劃與我使用EXECUTE IMMEDIATE調用過程時不同。這導致執行時間增加5倍。計劃之間的主要區別在於,當我立即使用執行時,優化器不會解除子查詢(我正在使用NOT EXISTS條件)。我們在大多數查詢中都使用基於規則優化器,但是這個提示使用索引,因此正在使用CBO(但是,我們不收集表上的統計信息)。我們正在運行Oracle9i企業版版本9.2.0.4.0 - 64位生產。Oracle EXECUTE IMMEDIATE更改查詢查詢計劃

舉例: 快速:

begin 
    package.procedure; 
end; 
/

慢:

begin 
    execute immediate 'begin package.' || proc_name || '; end;'; 
end; 
/

查詢:

SELECT            /*+ INDEX(A IDX_A_1) */ 
     a.store_cd, 
      b.itm_cd itm_cd, 
      CEIL ((new_date - a.dt)/7) week_num, 
      SUM (a.qty * b.demand_weighting * b.CONVERT) qty 
    FROM   a 
       INNER JOIN 
        b 
       ON (a.itm_cd = b.old_itm_cd) 
       INNER JOIN 
       (SELECT g.store_grp_cd, g.store_cd 
        FROM g, h 
        WHERE g.store_grp_cd = h.fdo_cd AND h.fdo_type = '1') d 
       ON (a.store_cd = d.store_cd AND b.store_grp_cd = d.store_grp_cd) 
      CROSS JOIN 
       dow 
    WHERE  a.dt BETWEEN dow.new_date - 91 AND dow.new_date - 1 
      AND a.sls_wr_cd = 'W' 
      AND b.demand_type = 'S' 
      AND b.old_itm_cd IS NOT NULL 
      AND NOT EXISTS 
       (SELECT 
         NULL 
        FROM f 
        WHERE f.store_grp_cd = a.store_cd 
          AND b.old_itm_cd = f.old_itm_cd) 
GROUP BY a.store_cd, b.itm_cd, CEIL ((dow.new_date - a.dt)/7) 

好解釋計劃:

OPERATION  OPTIONS   OBJECT_NAME  OBJECT_TYPE  ID  PARENT_ID 
SELECT STATEMENT            0  
SORT   GROUP BY          1  0 
NESTED LOOPS             2  1 
HASH JOIN  ANTI           3  2 
TABLE ACCESS BY INDEX ROWID H        4  3 
NESTED LOOPS             5  4 
NESTED LOOPS             6  5 
NESTED LOOPS             7  6 
TABLE ACCESS FULL   B        8  7 
TABLE ACCESS BY INDEX ROWID A        9  7 
INDEX   RANGE SCAN  IDX_A_1   UNIQUE   10  9 
INDEX   UNIQUE SCAN  G    UNIQUE   11  6 
INDEX   RANGE SCAN  H_UK   UNIQUE   12  5 
TABLE ACCESS FULL   F        13  3 
TABLE ACCESS FULL   DOW        14  2 

不好解釋計劃:

OPERATION  OPTIONS   OBJECT_NAME  OBJECT_TYPE  ID  PARENT_ID 
SELECT STATEMENT            0  
SORT   GROUP BY          1  0 
NESTED LOOPS             2  1 
NESTED LOOPS             3  2 
NESTED LOOPS             4  3 
NESTED LOOPS             5  4 
TABLE ACCESS FULL   B        6  5 
TABLE ACCESS BY INDEX ROWID A        7  5 
INDEX   RANGE SCAN  IDX_A_1   UNIQUE   8  7 
TABLE ACCESS FULL   F        9  8 
INDEX   UNIQUE SCAN  G    UNIQUE   10  4 
TABLE ACCESS BY INDEX ROWID H        11  3 
INDEX   RANGE SCAN  H_UK   UNIQUE   12  11 
TABLE ACCESS FULL   DOW        13  2 

在惡劣的解釋計劃子查詢不被嵌套的。我能夠通過給子查詢添加一個no_unnest提示來重現這個不好的計劃;但是,我無法使用unnest提示(使用立即執行運行該程序時)重現該良好計劃。其他提示正在被優化器考慮時使用立即執行而不是無條件的提示。

只有當我使用立即執行調用該過程時纔會出現此問題。如果我在查詢本身使用立即執行,它使用良好的計劃。

+0

我會認爲基於規則的oprimizer應該是一致的。 可能會添加一個提示,看看這是否也改變了計劃 - 驗證RBO實際上是有效的... – Randy 2010-05-07 16:15:49

+0

我們有一個提示,在查詢中已經使用了一個索引,這樣做會導致CBO被用來代替查詢?儘管如此,我還是試圖在子查詢中加入一些無關緊要的暗示,但這似乎並不令人滿意。 – Gunny 2010-05-07 16:23:57

+0

索引提示不會導致使用CBO。您可以使用FIRST_ROWS或ALL_ROWS提示來強制使用CBO,或使用RULE提示來強制使用RBO。 也許你應該發佈實際的SQL查詢和你看到的兩個不同的計劃。 – 2010-05-07 17:27:50

回答

1

事實證明,這是Oracle 9i中的一個已知錯誤。以下是錯誤報告中的文字。

,可執行立即帶來壞查詢計劃[ID 398605.1]

Modified 09-NOV-2006  Type PROBLEM  Status MODERATED 

該文件正在通過Oracle Support的快速可視化(RAV)過程中交付給你,所以一直沒有接受獨立的技術評論。

適用於: Oracle服務器 - 企業版 - 版本:9.2.0.6 可以在任何平臺上會出現此問題。

症狀 當通過立即執行運行過程時,生成的計劃與直接運行過程不同。

原因 這個問題的原因已經查明,並在未公開的Bug 2906307. 它是由一個事實,即在遞歸 深度大於1,從PLSQL發出的SQL語句可能會得到不同的執行計劃引起驗證到那些直接從SQL發佈的。 受此錯誤影響的優化器功能有多個(例如_unnest_subquery,_pred_move_around = true) 與這些功能相關的提示也可能被忽略。

此錯誤涉及與問題2871645相同的基本問題複雜視圖合併不會發生在 遞歸SQL>深度1,但複合視圖合併以外的其他功能。

錯誤2906307已作爲錯誤3182582的副本關閉SQL語句運行緩慢DBMS_JOB超過SQL * PLUS。 它是固定在10.2

解決方案 INSERT語句的使用提示BYPASS_RECURSIVE_CHECK: INSERT/* + BYPASS_RECURSIVE_CHECK */INTO表

參考 BUG:2871645 - 複雜視圖合併不會發生FOR RECURSIVE SQL> DEPTH 1 BUG:3182582 - SQL語句在SQL * PLUS中的DBMS_JOB中運行緩慢

+0

10.2.0.4中仍然存在類似的情況 – 2010-06-03 20:30:44

1

您已經使用ANSI連接語法,這將強制使用CBO (見http://jonathanlewis.wordpress.com/2008/03/20/ansi-sql/

「一旦你正在運行沒有統計基於成本的,也有小事各種可能足以在執行計劃中引起意外的行爲。「

+0

我試過使用此查詢使用ANSI和非ANSI連接。最初的查詢是非ANSI,但我最終粘貼了ANSI。我對這兩種風格仍然有同樣的問題。 – Gunny 2010-05-09 18:29:14

1

您可以採取幾個步驟。第一個是10046蹤跡。

理想情況下,我會在執行「好」和「壞」查詢的單個會話上開始跟蹤。跟蹤文件應該包含具有硬解析的兩個查詢。我會感興趣的是爲什麼第二個硬解析,因爲如果它有相同的SQL結構和相同的解析用戶,那麼第二個硬解析沒有太多的理由。同一個會話應該表示不存在來自不同內存設置的奇怪現象。

SQL不顯示任何變量的使用,所以應該沒有數據類型問題。所有列都綁定到表別名,因此似乎沒有將變量與列混淆的空間。

更極端的一步是10053蹤跡。喬納森劉易斯的網站上發佈了viewer。這可以讓你進入優化的內容,試圖找出不同計劃的原因。

從更廣泛的角度來看,9i幾乎已經死亡,RBO幾乎已經死亡。我會認真評估一個將應用程序遷移到CBO的項目。有些功能會迫使CBO被使用,如果沒有統計數據,這種問題將不斷出現。

1

事實證明,這是Oracle 9i中的一個已知錯誤。以下是錯誤報告中的文字。

,可執行立即帶來壞查詢計劃[ID 398605.1]

修改09-NOV-2006型問題的狀態主持

該文件正在通過Oracle Support的快速可視化交付給你(RAV)的過程,因此沒有經過獨立的技術審查。

適用於:Oracle Server - 企業版 - 版本:9.2.0.6在任何平臺上都可能發生此問題。

症狀當過程通過立即執行運行時,生成的計劃與直接運行過程時不同。

原因此問題的原因已在未發佈的錯誤2906307中識別並驗證。它是由PLSQL在遞歸深度大於1時發出的SQL語句可能會得到不同於直接從SQL。有多個優化器功能受此bug影響(例如_unnest_subquery,_pred_move_around = true)與功能相關的提示也可能被忽略。

此錯誤涵蓋了與錯誤2871645相同的基本問題複雜視圖合併不會發生遞歸SQL>深度1,但複合視圖合併以外的其他功能。

錯誤2906307已作爲錯誤3182582的副本關閉SQL語句運行緩慢DBMS_JOB超過SQL * PLUS。它是固定在10.2

解決方案對於insert語句中使用提示BYPASS_RECURSIVE_CHECK:INSERT/* + BYPASS_RECURSIVE_CHECK */INTO表

參考BUG:2871645 - 複雜視圖合併不會發生遞歸SQL>深度爲1個BUG:3182582 - SQL語句運行在DBMS_JOB比SQL * PLUS減少