キャッシュされている実行プランについて心配するのは正しいことです。
Martinは、プランがキャッシュされ、最初に実行されるときにロジックの特定のブランチに対して最適化されることを示す良い例を示しています。最初の実行後、別のパラメーターを使用してストアドプロシージャ(sproc)を呼び出し、実行フローが別のブランチを選択した場合でも、そのプランは再利用されます。これは非常に悪いことであり、パフォーマンスを低下させます。私はこれが何度も起こるのを見てきました、そして根本的な原因を見つけるのに時間がかかります。
この背後にある理由は「パラメータスニッフィング」と呼ばれ、調査する価値があります。
一般的に提案されている解決策(私はアドバイスしません)は、sprocをいくつかの小さなものに分割することです。sproc内でsprocを呼び出すと、その内部sprocは、渡されるパラメーターに最適化された実行プランを取得します。
正当な理由がない場合(正当な理由はモジュール性である)にsprocをいくつかの小さなものに分割することは、醜い回避策です。Martinは、スキーマに変更を加えることでステートメントを再コンパイルできることを示しています。ステートメントの最後にOPTION(RECOMPILE)を使用します。これは、すべての変数の現在の値を考慮に入れてステートメントの再コンパイルを行うようにオプティマイザーに指示します。パラメーターだけでなくローカル変数も考慮に入れられるため、良い計画と悪い計画を区別できます。
パラメータに応じて異なるwhere句を使用してクエリを作成するという質問に戻ります。次のパターンを使用します。
WHERE
(@parameter1 is null or col1 = @parameter1 )
AND
(@parameter2 is null or col2 = @parameter2 )
...
OPTION (RECOMPILE)
欠点は、このステートメントの実行プランがキャッシュされないことです(ただし、ステートメントのポイントまでのキャッシュには影響しません)。これは、コンパイル時間が必要になるため、sprocが何度も実行される場合に影響を与える可能性があります。考慮に入れます。生産品質データを使用してテストを実行すると、問題があるかどうかにかかわらず答えが得られます。
利点は、読みやすくエレガントなsprocをコーディングでき、オプティマイザーを間違った方向に設定できないことです。
覚えておくべきもう1つのオプションは、sprocレベル(ステートメントレベルではなく)レベルで実行プランのキャッシュを無効にできることです。これは、粒度が低く、さらに重要なことに、最適化時にローカル変数の値を考慮しません。
詳細については、
http://www.sommarskog.se/dyn-search-2005.htmlhttp:
//sqlinthewild.co.za/index.php/2009/03/19/catch-all-queries/をご覧ください。