SQL Server 2000で発生している問題を理解しようとしています。中程度のトランザクションWebサイトであり、customerIDを受け入れるsp_GetCurrentTransactions
というストアドプロシージャと2つの日付があります。
日付と顧客に応じて、このクエリは0から1000の行を返すことができます。
問題:私たちが経験したことは、特定のクライアントがそのストアドプロシージャを実行しようとすると、突然、特定のクライアントに対していくつかのエラー(通常はExecution Timeout Expired
または類似のエラー)が発生することです。したがって、クエリを調べてSSMSで実行し、30秒かかることがわかりました。そのため、ストアドプロシージャを再コンパイルし、-bang-を300ミリ秒で実行します。
私はこれについてDBAに話しました。ストアドプロシージャを作成したときに、データベースがクエリプランを作成したと彼は言っています。彼は、その一連のパラメーターについては適切な計画であると述べましたが、特定の一連のパラメーターをそれに投げると、その計画はそのデータにとって最良の計画ではなくなり、実行が遅くなることがわかります。
私に提示されたオプションは、ストアドプロシージャから問題のクエリを動的SQLに戻し、実行ごとに実行プランを作成することです。
これは私に一歩戻るような感じで、これを回避する方法があるはずだと感じています。この問題に対処する他の方法はありますか?
すべての応答を歓迎します。
この問題は、パラメータスニッフィングと呼ばれます。
SQL Serverのそれ以降のバージョンでは、OPTION (RECOMPILE)
またはOPTIMIZE FOR
ヒントなど、SQL Serverを扱う際のオプションが増えました。
ストアドプロシージャで変数を宣言し、変数にパラメーター値を割り当て、ほとんどの場合合理的に満足のいく計画を得ているように聞こえるように、パラメーターの代わりに変数を使用してみてください。
通常、最も壊滅的に悪い計画は、選択性が非常に高いパラメーター用にコンパイルされたものの、選択性が低いパラメーターで実行されたものです。
生成されたプランがこのアプローチでより堅牢であり、すべてのパラメーター値に満足できると仮定すると、JNKによって提案されたものに対するこのアプローチの利点は、すべての呼び出しでコンパイルコストが発生しないことです。
欠点は、一部の実行では、実行時間は、これらのパラメーター値に合わせて特別に調整された計画の場合よりも長くなる可能性があるため、コンパイル時間と実行時間のトレードオフです。
動的SQLを使用する代わりに、常にproc呼び出しを次のように変更できます。
EXEC Database.dbo.usp_Myprocedure 'Parameter' WITH RECOMPILE
WITH RECOMPILE
は、実行されるたびに実行プランの再コンパイルを強制します(ご想像のとおり!)。
ストアドプロシージャの定義にWITH RECOMPILE
を含めることもできます。
CREATE PROCEDURE usp.MyProcedure (Parameters)
WITH RECOMPILE
AS
...
また、オプティマイザと少し戦うことになるので、使用する予定のデータベースを決定することもできます。そのため、希望よりも脆弱になります。
テクニックはこれです-ストアドプロシージャを2つに分割します。1つはパラメータのセット用、もう1つはパラメータ用です。 where句をそれぞれに追加して、それらの間で可能なすべてのケースをカバーするようにします。クエリプランを見てください。一方はパラメータのセットに対して最適化し、もう一方は他のセットに対して最適化する必要があります。これを実現するためにクエリをいじる必要がある場合や、クエリでこれを実現できない場合があります。その場合、このアプローチは機能しません。
次に、元のストアドプロシージャでパラメーター値を確認し、前の段落の2つのストアドプロシージャの適切な1つにディスパッチします。
これは機能しますが、クエリに対してオプティマイザをより効率的に機能させることは一種のハックです。このようなすべてのハックと同様に、データベースの将来のバージョンでは、それは不要になるか、事態を悪化させる可能性さえあります。したがって、それが機能しても、それが価値があるかどうかを判断する必要があります。
SET FORCEPLAN
およびインデックスのヒント。
http://msdn.Microsoft.com/en-us/library/ms188344.aspx
基本的に、結合が発生する順序を選択できます。
SQLサーバーが正しいインデックスを使用するように、インデックスヒントを使用できます。
うーん...この1つのストアドプロシージャだけに焦点を当てている場合、キャッシュされた実行プランを使用すると、表示されている問題が発生することに驚かれるでしょう。顧客と2つの日付のパラメータのセットを使用して、ストアドプロシージャの実行計画を確認してください。より具体的なインデックスが役立つのだろうか-> customerIdのように、2つの日付のみか?
パフォーマンスの突然の低下は、おそらく統計が欠落している結果として生成された非効率的なクエリプランのように聞こえます。 「エラーと警告」イベントカテゴリを設定してSQL Serverプロファイラを実行し、欠落している統計に関する警告があるかどうかを確認します。
また、インデックスが欠落している可能性があります。または、インデックスが断片化されすぎてSQL Serverで使用できず、テーブルスキャンで生成されるI/Oが少ないと考えられるため、インデックスをデフラグする必要がある場合があります。
@JNKはストアドプロシージャについて重要な点を提起します-これらは事前にコンパイルされ、クエリプランはストアドプロシージャと共に保存されます。
WITH RECOMPILEを使用することに必ずしも同意しません。この場合、クエリプランが格納されて再利用されるメリットが失われます。これが必要な場合があります。つまり、基になるテーブルの分散統計が呼び出し間で大きく異なる場合ですが、通常、テーブル内のデータが成熟すると、テーブル内のデータの分散は最小限に変化します。
要約すると、