65

しばらく前に、ユーザーの1人に対してかなり多く実行したクエリがありました。それはまだ進化して微調整されていましたが、最終的には安定して実行されたので、そこからストアドプロシージャを作成しました。

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

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

[背景、SQLServer2005を実行しています。]

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

ストアドプロシージャの一部を2番目のプロシージャに抽象化し、この新しい内部プロシージャの呼び出しを、外部プロシージャと呼ばれる既存の外部プロシージャにラップしました。これは、元のクエリと同じくらい高速でした。

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

のボーナスクレジット

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

8 に答える 8

55

参考までに-SQL2005を使用していて、パラメータを使用してプロシージャを格納する場合は、他のことに注意する必要があります。

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

usp_QueryMyDataByState 'Rhode Island'

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

usp_QueryMyDataByState 'Texas'

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

これがクエリプランの出番です。SQLServer2008は、どのパラメーターが最初に呼び出されても、DBAが特定のクエリプランを長期的に固定するのに役立つ多くの新機能を提供します。

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

于 2008-10-19T01:36:33.493 に答える
27

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

CREATE PROCEDURE uspParameterSniffingAvoidance
    @SniffedFormalParameter int
AS
BEGIN

    DECLARE @SniffAvoidingLocalParameter int
    SET @SniffAvoidingLocalParameter = @SniffedFormalParameter

    --Work w/ @SniffAvoidingLocalParameter in sproc body 
    -- ...
于 2008-10-19T00:38:02.127 に答える
27

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

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

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

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

于 2008-10-17T11:51:10.527 に答える
5

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

于 2010-11-09T00:25:41.063 に答える
5

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

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

これは、次のいずれかで回避できます。

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

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

SQL Server が (次善の) 実行計画をキャッシュおよび再利用する方法について、さらに調査を行う必要があります。

于 2008-10-22T09:27:19.847 に答える
0

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

于 2013-03-26T12:55:41.597 に答える
-1

非常にシンプルでソートされたクエリ オプティマイザーは、頻繁に実行されるクエリに対して古いクエリ プランを使用します。しかし、実際にはデータのサイズも増加しているため、その時点で新しい最適化されたプランが必要であり、クエリの古いプランを使用するクエリオプティマイザーがまだ必要です。これは、パラメータ スニッフィングと呼ばれます。これに関する詳細な投稿も作成しました。次の URL にアクセスしてください: http://www.dbrnd.com/2015/05/sql-server-parameter-sniffing/

于 2015-08-21T19:57:41.410 に答える
-2

ストア プロシージャをバッチとして実行するように変更すると、速度が向上します。

バッチファイルの選択:

exec ('select * from order where  order id ='''+ @ordersID')

通常のストアド プロシージャの代わりに、次を選択します。

select * from order where  order id = @ordersID

as パラメーターを渡すだけで、nvarcharより迅速な結果が得られるはずです。

于 2012-07-17T14:12:53.930 に答える