web-dev-qa-db-ja.com

SQL Serverのパラメータースニッフィング(またはスプーフィング)

少し前に、あるユーザーに対して非常に多くのクエリを実行しました。まだ進化と調整が行われていましたが、最終的には安定し、非常に迅速に実行されるため、そこからストアドプロシージャを作成しました。

これまでのところ、とても正常です。

ただし、ストアドプロシージャは非常に低速でした。クエリとprocの間に実質的な違いはありませんが、速度の変化は大規模でした。

[背景、SQL Server 2005を実行しています。]

フレンドリーなローカルDBA(ここではもう働いていません)は、ストアドプロシージャを1回見て、「パラメータースプーフィング!」と言いました。 (編集:「パラメータスニッフィング」としても知られているようですが、検索しようとしたときのGoogleヒットの不足を説明するかもしれません。)

ストアドプロシージャの一部を2番目のプロシージャに抽象化し、この新しい内部プロシージャの呼び出しを外部プロシージャと呼ばれる既存の外部プロシージャにラップしました。

それで、何が得られますか?誰かがパラメータのなりすましを説明できますか?

のボーナスクレジット

  • それを避ける方法を強調する
  • 考えられる原因を認識する方法を提案する
  • 代替戦略について話し合う状況を緩和するための統計、インデックス、キー
63
Unsliced

参考までに、SQL 2005とパラメーター付きストアドプロシージャを使用している場合は、他のことに注意する必要があります。

SQL Serverは、使用される最初のパラメーターを使用してストアドプロシージャの実行プランをコンパイルします。これを実行すると:

usp_QueryMyDataByState 'Rhode Island'

実行計画は、小さな状態のデータで最適に機能します。しかし、誰かが振り向いて実行した場合:

usp_QueryMyDataByState 'Texas'

ロードアイランドサイズのデータ​​用に設計された実行計画は、テキサスサイズのデータ​​ほど効率的ではない場合があります。新しく生成された実行プランは、最初に使用されたパラメーターをターゲットとするため、サーバーを再起動すると驚くべき結果が得られる可能性があります。必ずしも最適なものではありません。統計は再構築される場合のように、それを行う大きな理由があるまで、計画は再コンパイルされません。

これがクエリプランの出番です。SQLServer 2008は、最初に呼び出されるパラメーターに関係なく、DBAが特定のクエリプランを長期にわたって適切に固定するのに役立つ多くの新機能を提供します。

私の懸念は、ストアドプロシージャを再構築するときに、実行計画を強制的に再コンパイルすることです。お気に入りのパラメーターを使用して呼び出しましたが、もちろん高速でしたが、問題はストアドプロシージャではなかった可能性があります。ストアドプロシージャは、ある時点で異常なパラメータセットを使用して再コンパイルされたため、非効率的なクエリプランであった可能性があります。何も修正していない可能性があり、次回サーバーが再起動したとき、またはクエリプランが再コンパイルされたときに同じ問題に直面する可能性があります。

53
Brent Ozar

はい、パラメータスニッフィングを意味すると思います。これは、クエリに最適な実行プランを選択できるように、SQL Serverオプティマイザがパラメータ値/範囲を把握しようとする手法です。場合によっては、SQL Serverのパラメータースニッフィングが不十分で、クエリに最適な実行プランが選択されないことがあります。

このブログ記事 http://blogs.msdn.com/queryoptteam/archive/2006/03/31/565991.aspx には十分な説明があると思います。

この例のDBAは、クエリを別のsprocに別の手続きコンテキストに移動するためにオプション#4を選択したようです。

元のsprocでwith recompileを使用するか、パラメータでoptimize forオプションを使用することもできます。

26
nkav

これを高速化する簡単な方法は、sprocの最初の段階で入力パラメーターをローカルパラメーターに再割り当てすることです。

CREATE PROCEDURE uspParameterSniffingAvoidance
    @SniffedFormalParameter int
AS
BEGIN

    DECLARE @SniffAvoidingLocalParameter int
    SET @SniffAvoidingLocalParameter = @SniffedFormalParameter

    --Work w/ @SniffAvoidingLocalParameter in sproc body 
    -- ...
24
6eorge Jetson

私の経験では、パラメータースニッフィングの最適なソリューションは「動的SQL」です。注意すべき2つの重要な点は、1。動的SQLクエリでパラメーターを使用する必要があること、2。各パラメーター値の実行計画を保存するsp_executesql(sp_executeではなく)を使用する必要があることです。

4
Sadhir

パラメータスニッフィングは、SQL Serverがストアドプロシージャのクエリ実行プランを最適化するために使用する手法です。ストアドプロシージャを最初に呼び出すとき、SQL Serverは呼び出しの指定されたパラメーター値を見て、パラメーター値に基づいて使用するインデックスを決定します。

したがって、最初の呼び出しにあまり一般的なパラメーターが含まれていない場合、SQL Serverは、ストアドプロシージャの次の呼び出しに関して、最適ではない実行計画を選択して格納する場合があります。

あなたはこれを回避することができます

  • WITH RECOMPILEを使用
  • パラメータ値をストアドプロシージャ内のローカル変数にコピーし、クエリでローカル変数を使用します。

ストアドプロシージャをまったく使用せず、クエリをサーバーに直接送信することをお勧めします。私は最近、実際の解決策がまだない同じ問題に遭遇しました。一部のクエリでは、ローカル変数へのコピーが適切な実行プランに戻るのに役立ちます。一部のクエリでは、ローカル変数でパフォーマンスが低下します。

SQL Serverが(最適ではない)実行プランをキャッシュして再利用する方法について、さらに調査する必要があります。

4
Jan

同様の問題がありました。ストアドプロシージャの実行計画には30〜40秒かかりました。クエリウィンドウでSP Statementsを使用してみましたが、実行に数ミリ秒かかりました。その後、ストアドプロシージャ内でローカル変数を宣言し、パラメータの値をローカル変数に転送しました。 SP実行は非常に高速であり、同じSPは30〜40秒ではなく数ミリ秒以内に実行されます。