3

EXECUTEIMMEDIATEを使用して呼び出しているストアドプロシージャがあります。私が直面している問題は、プロシージャを直接呼び出す場合と、EXECUTEIMMEDIATEを使用してプロシージャを呼び出す場合とでExplain計画が異なることです。これにより、実行時間が5倍になります。プラン間の主な違いは、すぐに実行を使用すると、オプティマイザーがサブクエリのネストを解除しないことです(NOT EXISTS条件を使用しています)。ここではほとんどのクエリでルールベースのオプティマイザーを使用していますが、これにはインデックスを使用するためのヒントがあり、CBOが使用されています(ただし、テーブルの統計は収集されません)。Oracle9iEnterpriseEditionリリース9.2.0.4.0-64ビット本番環境を実行しています。

例:高速:

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)

良い説明計画:

操作オプションOBJECT_NAMEOBJECT_TYPEID PARENT_ID
ステートメント0を選択       
グループを10で並べ替える
ネストされたループ21
HASH JOIN ANTI 3 2
インデックスROWIDH43によるテーブルアクセス
ネストされたループ54
ネストされたループ65
ネストされたループ76
テーブルアクセスフルB87
INDEX ROWID A97によるテーブルアクセス
インデックス範囲スキャンIDX_A_1一意109
INDEX UNIQUE SCAN G UNIQUE 11 6
INDEX RANGE SCAN H_UK UNIQUE 12 5
テーブルアクセスフルF133
テーブルアクセスフルダウ142

悪い説明計画:

操作オプションOBJECT_NAMEOBJECT_TYPEID PARENT_ID
ステートメント0を選択       
グループを10で並べ替える
ネストされたループ21
ネストされたループ32
ネストされたループ43
ネストされたループ54
テーブルアクセスフルB65
INDEX ROWID A75によるテーブルアクセス
インデックス範囲スキャンIDX_A_1一意87
テーブルアクセスフルF98
INDEX UNIQUE SCAN G UNIQUE 10 4
インデックスROWIDH113によるテーブルアクセス
INDEX RANGE SCAN H_UK UNIQUE 12 11
テーブルアクセスフルダウ132

悪い説明プランでは、サブクエリはネストされていません。サブクエリにno_unnestヒントを追加することで、悪い計画を再現することができました。ただし、(すぐに実行を使用してプロシージャを実行する場合)最も悪いヒントを使用して適切な計画を再現することはできませんでした。他のヒントは、最悪のヒントではなく、即時実行を使用するときにオプティマイザーによって考慮されています。

この問題は、executeimmediateを使用してプロシージャを呼び出す場合にのみ発生します。クエリ自体に対して即時実行を使用する場合は、適切な計画が使用されます。

4

4 に答える 4

1

これはOracle9iの既知のバグであることが判明しました。以下はバグレポートのテキストです。

即時実行は不正なクエリプランを提供します[ID398605.1]

Modified 09-NOV-2006     Type PROBLEM     Status MODERATED

このドキュメントは、OracleSupportのRapidVisibility(RaV)プロセスを介して提供されているため、独立した技術レビューの対象ではありません。

適用対象: Oracle Server-Enterprise Edition-バージョン:9.2.0.6この問題は、どのプラットフォームでも発生する可能性があります。

症状 プロシージャを実行してすぐに実行する場合、作成される計画は、プロシージャを直接実行する場合とは異なります。

原因 この問題の原因は、未公開のバグ2906307で特定および検証されています。これは、PLSQLから再帰的な深さが1より大きいSQL文がSQLから直接発行されたものとは異なる実行計画を取得する可能性があるためです。このバグの影響を受けるオプティマイザー機能は複数あります(たとえば、_unnest_subquery、_pred_move_around = true)。機能に関連するヒントも無視される場合があります。

このバグは、バグ2871645と同じ基本的な問題をカバーしています。複雑なビューのマージは、再帰SQL>深さ1では発生しませんが、複雑なビューのマージ以外の機能では発生しません。

バグ2906307は、バグ3182582の複製として閉じられます。SQLステートメントは、SQL*PLUSよりもDBMS_JOBで遅くなります。10.2で修正されました

解決策 挿入ステートメントには、ヒントBYPASS_RECURSIVE_CHECKを使用します。INSERT/ * + BYPASS_RECURSIVE_CHECK */INTOテーブル

参照 BUG:2871645-複雑なビューのマージが再帰SQL> DEPTH 1で発生しないBUG:3182582-SQLステートメントの実行がDBMS_JOBでSQL*PLUSよりも遅い

于 2010-05-13T21:01:31.817 に答える
1

実行できる手順がいくつかあります。1 つ目は 10046 トレースです。

理想的には、「良い」クエリと「悪い」クエリの両方を実行する単一のセッションでトレースを開始します。トレース ファイルには、ハード パースを使用した両方のクエリが含まれている必要があります。同じSQL構造と同じ解析ユーザーを持っている場合、2番目のハードパースの理由はあまりないので、2番目のハードパースがある理由に興味があります。同じセッションは、異なるメモリ設定などからの奇妙な点がないことを意味するはずです.

SQL は変数の使用を示していないため、データ型の問題はないはずです。すべての列はテーブル エイリアスに「関連付けられている」ため、変数と列を混同する余地はないようです。

より極端なステップは 10053 トレースです。Jonathan Lewis のサイトに投稿されたビューアがあります。これにより、最適化の本質を理解して、異なる計画の理由を突き止めようとすることができます。

広い視野で見ると、9i はほとんど死んでおり、RBO もほとんど死んでいます。アプリを CBO に移行するプロジェクトを真剣に評価しています。CBO の使用を強制する機能があり、統計がなければこのような問題が発生し続けます。

于 2010-05-09T23:11:12.900 に答える
1

CBO の使用を強制する ANSI 結合構文を使用しました ( http://jonathanlewis.wordpress.com/2008/03/20/ansi-sql/を参照) 。

「統計なしでコストベースを実行すると、実行計画で予期しない動作を引き起こすのに十分なあらゆる種類の小さなことが発生します。」

于 2010-05-08T05:58:56.173 に答える
1

これは、Oracle 9i の既知のバグであることが判明しました。以下はバグレポートのテキストです。

Execute Immediate で不適切なクエリ プランが生成される [ID 398605.1]

2006 年 11 月 9 日変更 タイプ 問題 ステータス 中程度

このドキュメントは、Oracle サポートの Rapid Visibility (RaV) プロセスを介して提供されているため、独立した技術レビューの対象ではありません。

適用対象: Oracle Server - Enterprise Edition - バージョン: 9.2.0.6 この問題は、どのプラットフォームでも発生する可能性があります。

症状 プロシージャーが execute immediately を介して実行される場合、生成されるプランは、プロシージャーが直接実行される場合とは異なります。

原因 この問題の原因は、未公開のバグ 2906307 で特定および検証されています。これは、再帰的な深さが 1 より大きい PLSQL から発行された SQL ステートメントが、SQL から直接発行されたものとは異なる実行計画を取得する可能性があるためです。このバグの影響を受けるオプティマイザ機能は複数あります (たとえば、_unnest_subquery,_pred_move_around=true)。機能に関連するヒントも無視される場合があります。

このバグは、Bug 2871645 再帰 SQL > 深さ 1 では複雑なビューのマージが発生しないが、複雑なビューのマージ以外の機能では発生しないという基本的な問題をカバーしています。

Bug 2906307 は Bug 3182582 SQL STATEMENT RUN SLOWER IN DBMS_JOB THAN IN SQL*PLUS の複製としてクローズされています。10.2 で修正されました。

解決法 INSERT ステートメントの場合は、ヒント BYPASS_RECURSIVE_CHECK: INSERT /*+ BYPASS_RECURSIVE_CHECK */ INTO table を使用します。

BUG:2871645 - 複雑なビューのマージは、再帰的 SQL では発生しません > 深さ 1 BUG:3182582 - SQL*PLUS よりも DBMS_JOB での SQL ステートメントの実行が遅い

于 2010-12-09T10:21:25.417 に答える