質問

状況

Oracle11.2.0.2.0の大量のデータに対する中規模のクエリのクエリ実行プランに問題があります。物事をスピードアップするために、私はおおよそ次のようなことをする範囲フィルターを導入しました: ジェネラコディセタグプレ

ご覧のとおり、オプションの組織番号の範囲を使用して、JOINorganisationsを制限したいと思います。クライアントコードは、制限付き(高速と思われる)または制限なし(非常に遅い)でDO_STUFFを呼び出すことができます。

トラブル

問題は、PL / SQLが上記のorg_fromおよびorg_toパラメータのバインド変数を作成することです。これは、ほとんどの場合に予想されることです。 ジェネラコディセタグプレ

回避策

この場合のみ、値をインライン化するだけで、つまりOracleによって実行されるクエリが実際に次のようなものである場合に、クエリ実行プランがはるかに優れていると測定しました。 ジェネラコディセタグプレ

「たくさん」とは、5〜10倍速いことを意味します。クエリが実行されることは非常にまれであることに注意してください。つまり、月に1回です。したがって、実行プランをキャッシュする必要はありません。

私の質問
  • PL / SQLで値をインライン化するにはどうすればよいですか? EXECUTE IMMEDIATE について知っていますが、 PL / SQLはクエリをコンパイルし、文字列の連結は行いません。

  • 偶然に起こったことを測定しただけですか、それとも変数のインライン化の方が実際に優れていると思いますか(この場合)?私が尋ねる理由は、バインド変数がOracleに一般的な実行プランを考案させるのに対し、インライン値は非常に特定の列とインデックスの統計を分析できると思うからです。ですから、これは単なる偶然ではないと想像できます。

  • 何か足りないのですか?変数のインライン化以外に、クエリ実行プランの改善を実現するまったく別の方法があるかもしれません(私もかなりの数のヒントを試しましたが、その分野の専門家ではありません)?

役に立ちましたか?

解決

あなたが言ったコメントの1つ:

"また、さまざまなバインド値を確認しました。 バインド変数を使用すると、完全になります テーブルスキャン、ハードコードされたもの 値、計画ははるかに良く見えます。」

2つのパスがあります。パラメータにNULLを渡すと、すべてのレコードが選択されます。このような状況では、全表スキャンがデータを取得する最も効率的な方法です。値を渡すと、情報の小さなサブセットのみを選択するため、インデックス付きの読み取りがより効率的になる可能性があります。

バインド変数を使用してクエリを作成する場合、オプティマイザは決定を下す必要があります。ほとんどの場合、値を渡すか、nullを渡すと想定する必要がありますか?難しい。つまり、別の見方をします。レコードのサブセットのみを選択する必要がある場合に全表スキャンを実行するのは非効率的ですか、それともすべてのレコードを選択する必要がある場合にインデックス付き読み取りを実行するのは非効率的ですか。

オプティマイザーは、すべての不測の事態をカバーするための最も非効率的な操作であるとして、全表スキャンに対応しているようです。

一方、値をハードコーディングすると、オプティマイザーは、10 IS NULLがFALSEと評価されることをすぐに認識します。そのため、インデックス付きの読み取りを使用して目的のサブセットレコードを見つけることのメリットを比較検討できます。


では、どうすればよいですか?このクエリは月に1回しか実行されないということですが、ビジネスプロセスを少し変更するだけで、すべての組織に1つ、組織のサブセットに1つ、個別のクエリを作成できると思います。


"ところで、:R1 ISNULL句を削除します 実行計画は変更されません 多く、それは私を他の人に残します OR条件の側、:R1 <= NULLが意味をなさないorg.no とにかく、org.noはNULLではないので」

わかりました。つまり、範囲を指定するバインド変数のペアがあります。 値の分布に応じて、さまざまな範囲がさまざまな実行プランに適合する場合があります。つまり、この範囲は(おそらく)インデックス付き範囲スキャンに適しています... ジェネラコディセタグプレ

...これは、全表スキャンにより適している可能性があります... ジェネラコディセタグプレ

ここで、Bind VariablePeekingが役立ちます。

(もちろん、値の分布によって異なります)。

他のヒント

クエリプランは実際には一貫して異なるため、オプティマイザのカーディナリティの見積もりが何らかの理由でオフになっていることを意味します。クエリプランから、バインド変数が使用されている場合、オプティマイザーが条件の選択が不十分であると予想していることを確認できますか? 11.2を使用しているため、Oracleはアダプティブカーソル共有」なので、バインド変数のピークの問題にはなりません(テストで、バインド変数を使用してバージョンを何度も呼び出し、NO値が異なると仮定します。

良い計画のカーディナリティの見積もりは実際に正しいですか? NO列の統計は正確であるとおっしゃっていましたが、たとえば、通常の統計収集プロセスでは更新されない可能性のある漂遊ヒストグラムが疑われます。

クエリでヒントを使用して、特定のインデックスを強制的に使用することができます(ただし、保存されたアウトラインまたはオプティマイザプランの安定性が望ましいでしょう)。これらのオプションはいずれも、動的SQLに頼るよりも望ましいでしょう。

ただし、もう1つのテストは、SQL99結合構文をOracleの古い構文に置き換えることです。 ジェネラコディセタグプレ

明らかに何も変更されるべきではありませんが、SQL 99構文にパーサーの問題があったため、確認する必要があります。

のようなにおいがしますBind Peeking ですが、私はOracle 10しか使用していないため、11にも同じ問題が存在するとは言えません。

これは、SQLPlanの安定性と組み合わせた、アダプティブカーソル共有の必要性によく似ています。 何が起こっているのかというと、capture_sql_plan_baselines parameter is trueだと思います。そして、use_sql_plan_baselinesについても同じです。これが当てはまる場合、次のことが起こっています。

  1. クエリが最初に開始されたときに解析され、新しいプランが取得されます。
  2. 2回目は、このプランは承認済みプランとしてsql_plan_baselinesに保存されます。
  3. このクエリの後続のすべての実行では、バインド変数が何であるかに関係なく、このプランが使用されます。

    アダプティブカーソル共有がすでにアクティブになっている場合、オプティマイザは新しい/より良いプランを生成し、それをsql_plan_baselinesに保存しますが、誰かがこの新しいプランを受け入れ可能な代替プランとして受け入れるまで、それを使用できません。 dba_sql_plan_baselinesをチェックし、クエリにaccepted = 'NO' and verified = nullのエントリがあるかどうかを確認します dbms_spm.evolveを使用して新しい計画を発展させ、計画のパフォーマンスが新しい計画がない場合よりも少なくとも1.5倍優れている場合は、自動的に受け入れさせることができます。

    これがお役に立てば幸いです。

これをコメントとして追加しましたが、ここでも提供します。これが過度に単純化されていないことを願っています。詳細な応答を見ると、正確な問題を誤解している可能性がありますが、とにかく...

組織テーブルに数値として定義された列番号(org.no)があるようです。ハードコードされた例では、数値を使用して比較を行います。 ジェネラコディセタグプレ

手順では、 varchar2 を渡します: ジェネラコディセタグプレ

したがって、varchar2を数値と比較するには、 Oracleが変換を実行する必要があります。これにより、フルスキャンが発生する可能性があります。

解決策: procを変更して数値を渡す

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top