アドホックで実行した場合とストアドプロシージャで実行した場合、コードは異なるプランを作成します


9

ストアドプロシージャ内で実行するときに不適切なプランを使用する削除ステートメントがありますが、アドホックで実行するときにはるかに優れたプランを選択しています。

クエリで使用されるテーブルのすべてのインデックスを再構築し、すべてのキャッシュを削除しました。オプティマイザは引き続き、ストアドプロシージャに対して誤ったプランを選択します。

オプティマイザがストアドプロシージャとアドホックSQLで異なる実行プランを使用している理由を知りたいのですが。

更新:私はそれが結局のところパラメータだったに違いない-私がハードコードされた変数でアドホックコードを実行したとき、私は正しい値(それは日付であり、1年前の値です)で「悪い」計画を得ることができます「良い」計画を生み出すようです)。次に、クエリヒントを使用して、プロシージャに "適切な"プランを強制しようとします。

解決策:OPTIMIZE FOR UNKNOWNヒントを使用して、目的の計画を取得することになりました。


おそらくパラメータスニッフィングです。クエリはそのWHERE句の変数を参照していますか?
Nick Chammas、2011年

4
コードを追加していただけませんか
gbn

また、どこかに計画を投稿してください。現状では、計画が異なる理由を正確に説明するのはかなり難しいでしょう。
Aaron Bertrand

OK、詳細:少し難読化するまで、計画とコードを投稿することはできません。私はそれらをいくつかで立ち上げるようにします。ストアドプロシージャ(悪い)の計画は、大きなテーブル(全体、すべてのパーティション)のクラスター化インデックススキャンを実行します。次に、ループを使用して小さなテーブルから行を検索し、小さなテーブルから削除します。
msgisme

アドホックコード(良い)の計画では、小さなテーブル(5〜10行しかない)のテーブルスキャンを実行し、大きなテーブルの非クラスター化インデックスを使用して、PKでチェックする必要がある行を見つけます。大きなテーブルの。できるだけ早く実際の計画を立てようと思います。
msgisme '10

回答:


5

ユージュアル・サスペクツ:

  1. アドホックの定数、コードのパラメーター
  2. コード内のデータ型の不一致
  3. パラメータスニッフィング

ポイント1:オプティマイザは定数の最適な計画を選択できます。
定数を変更する=計画を変更する。パラメータ化されたプレンは復活可能です

ポイント2では
、nvarcharパラメータと比較したvarchar列などのデータ型の優先順位のため、暗黙的な変換が導入されます

ポイント3:パラメーターマスキングまたはOPTIMIZE FOR UNKNOWNを使用する
編集:テストするには、ストアドプロシージャを実行し、sp_updatestatsを実行して、再度実行します。これは、キャッシュされたプランを無効にし、プランキャッシュをクリアするよりも優れています

編集:jcolebrandのコメントの後

いくつかの方法でスニッフィングを無効にすることができます。メイン3は

  • 再コンパイル。これはばかげたIMOです。
  • 不明の最適化(sic)
  • パラメータマスキング

パラメータマスキング:

DECLARE @MaskedParam varchar(10)
SELECT @MaskedParam = @SignaureParam

SELECT...WHERE column = @MaskedParam

マスキングとOPTIMIZEヒントの効果は同じです(理由はさまざまです)。つまり、オプティマイザは統計とデータ分布を使用する必要があります(注:まだMark Storey-Smithによるテスト中、独自のメリットでパラメータを評価しますか? 彼らが最後に呼んだものではなく、オプティマイザは再コンパイルすることもしないこともできます。SQL Server 2005はステートメントレベルの再コンパイルを追加したので、影響は少なくなりました

さて、なぜ「スニッフィング」パラメータを持つプランが「マスクされた」/「不明な」パラメータと比較して「スティッキー」であるのか、私にはわかりません。

SQL Server 2000以降、最も単純なコードを除いて、すべてパラメーターマスキングを使用しています。より複雑なコードで発生する可能性があることを指摘しました。そして、私の古い仕事で、私は計画パラメーターのデフォルトを変更できるいくつかのレポートプロシージャを持っています。「カーゴカルト」のアプローチはサポートコールよりも簡単だと思います。

チャットの後、2011年10月12日2を編集

  • パラメータマスキングとOPTIMIZE FOR UNKNOWNは、私の知る限り同じ効果があります
    。ヒントはマスキングよりもきれいですが、SQL Server 2008で追加されました。

  • パラメータのスニッフィングはコンパイル時に行われます。
    WITH RECOMPILEは、実行ごとに新しいプランを生成します。つまり、デフォルトの選択が適切でないと、計画に影響が出ます。私の最後の仕事で、これをいくつかのレポートコードで簡単に示すことができました。パラメーターのデフォルトを変更すると、提供されたパラメーターに関係なく計画が変更されました。

  • このMS Connectの記事は興味深いです:ストアドプロシージャ内でのインデックスの使用が最適ではありません(以下のSOの回答の1つで言及されています)

  • ボブ・ボーケミンもそれについて言及している

未解決の問題

  • WITH RECOMPILEでもスニッフィングは適用されますか?つまり、オプティマイザが計画を破棄することを知っている場合、それは再利用を目的としていますか?

  • なぜスニッフィングされたプランは「スティッキー」なのですか

SOからのリンク:


1. spのparamはコードの変数です2.繰り返しますが、同じデータ型3.両方を多種多様なパラメーターで実行しましたが、毎回同じプランを取得します。試行するたびにキャッシュをクリアしました。
msgisme

1
Re:ポイント3. SQL ステートメントを既存の計画を無視するように強制するために、OPTION (RECOMPILE)またはプロシージャ全体でステートメントを実行することもできWITH RECOMPILEます。
Nick Chammas、2011年

3
ところでOPTIMIZEMicrosoftはアメリカの会社ですから。:)
Nick Chammas、2011年

1
@GBNパラメータスニッフィングの防止/無効化についての考えは?
jcolebrand

1
@jcolebrand:単純な答えは「いいえ」:-)
gbn

2

接続プラン用に設定したANSI設定は、実行プランの選択における役割であることを忘れないでください。アプリがストアドプロシージャを呼び出すと、おそらくSSMS接続とは異なるANSI設定になります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.