いくつかのストアドプロシージャを実行するレポートページを備えたASP.Netアプリケーションがあります。レポートの実行が非常に遅いため、ユーザーがより長い日付範囲を選択するとタイムアウトになるという本番システムに問題があります。
スローダウンが発生した場合、すべてのストアドプロシージャが影響するテーブルで_EXEC sp_recompile 'CrucialTable'
_を実行し、すぐに長い日付範囲のレポートを実行することで、機能を復元できます。これはしばらくの間問題を解決しますが、ゆっくりと忍び寄ります。
実行プランが悪いと思いましたので、ストアドプロシージャに_WITH RECOMPILE
_を追加しましたが、残念ながら問題は解決しませんでした。
違いがある場合は、SQL Azureを使用しています。
[〜#〜]更新[〜#〜]
再コンパイルオプションがまだ不足しているSPをいくつか見つけたので、これが追加され、新しい問題が発生しました。長い日付範囲のレポートは適切に実行されますが(4秒未満ですが、発生しているクランチの量を考えると問題ありません)、奇妙なことに、短い範囲のレポートが恐ろしく実行されています。たとえば、2年間のトランザクションをカバーするレポートには約3.5秒かかりますが、2週間には20秒かかります。
更新2
開発マシンで問題を再現し、実行計画を確認しました。 OPTION(RECOMPILE)
やOPTIMIZE
のようなオプションの組み合わせを多数試しましたが、クエリ自体は非常に高速に実行されます。
問題はそれです
クエリは実行中にMemoryGrantをxx秒待機する必要がありました
xxは、実行に応じて20〜90秒の範囲でした。
当時は他のクエリが実行されておらず、開発マシンには十分なRAMがあるため、これは珍しい印象を受けました。実行プランは欠落しているインデックスも提案したので、それを試して追加して、それが役立つかどうかを確認します。
更新
いくつかの再コンパイル/最適化オプションを試してみましたが、まだ解決策がありません。
基本的に、ストアドプロシージャにはすべて再コンパイルオプションがあり、テストでは、ビッグデータでもすべてがうまく機能します(クエリは1秒もかかりません)。 MemoryGrantの私の最初の問題は停止しました。それは、それが実行されていたマシンが多くのアプリケーションを開いていて、空きRAMが少なかったためだと思います。
本番環境では、すべてのSPに同じ再コンパイルオプションが設定されていますが、残念ながら、短距離クエリは非常に遅くなっています。私はSSMSを使用して同じSPを運用DBに実行し(ARITHABORTをOFFに設定して同様の接続をシミュレートしました)、それらは長距離または短距離に関係なく実質的に瞬時に実行されます。
本番環境のアプリケーションから短距離レポートを実行すると、_sys.dm_exec_query_memory_grants
_テーブルに約12秒間エントリがあります。完全なレポートは、エントリが消えてから完了までにさらに14秒以上かかります。
あなたが説明していることは、私にパラメータを盗聴するような音です。プランがキャッシュに見つからない場合、SQL Serverはプロシージャの実行プランをキャッシュするため、パラメータスニッフィングが発生します。以降の実行では、そのバージョンのプランが使用されます。ほとんどの場合、コンパイル時間が不要になるため、これは望ましいことです。ただし、プロシージャのクエリによってアクセスされるデータの特性がさまざまなパラメータが渡されたときに大幅に変化する場合、結果は非常に低いパフォーマンスになる可能性があります。
短い日付範囲と長い範囲のランタイムの説明は、そのパターンに完全に適合します。クエリオプティマイザーが2つのシナリオで異なるインデックスを選択していると思います。
あなたはあなたのソリューションのための正しい軌道に乗っています。 _WITH RECOMPILE
_は、場合によってはパラメータースニッフィングを解決できますが、再コンパイルは実行ごとに支払うコストが高くなります。個々のクエリでのOPTION(RECOMPILE)
は間違いなく役立ち、時には最良の答えですが、やはり高コストになります。 OPTION(OPTIMIZE FOR UNKNOWN)
も別の可能性ですが、一貫性のある計画を提供することで問題を解決します(ただし、恐ろしく非効率的かもしれません)。
これらの記事を確認することから始めます。これらの記事では、短い答えでパラメーターのスニッフィングを私が説明するよりもはるかによく説明しています。
次に、プロシージャの実行プランを確認し、実行間で最も変化する特定のクエリを探します。プロシージャ全体ではなく、OPTION(RECOMPILE)
、OPTION(OPTIMIZE FOR UNKNOWN)
、またはKimberlyの_sp_executesql
_メソッドを試してください。