T-SQLでIFを使用すると、実行計画のキャッシングが弱くなるか壊れますか?


20

t-SQLバッチでIFステートメントを使用すると、パフォーマンスが低下することが示唆されています。このアサーションを確認または検証しようとしています。SQL Server 2005および2008を使用しています。

アサーションは、次のバッチでのことです:-

IF @parameter = 0
 BEGIN
  SELECT ... something
 END

ELSE
 BEGIN
  SELECT ... something else
 END

次の実行には別のブランチが必要な場合があるため、SQL Serverは生成された実行プランを再利用できません。これは、現在の実行で必要なブランチを既に決定できることに基づいて、SQL Serverが実行プランから1つのブランチを完全に削除することを意味します。これは本当ですか?

さらに、この場合に何が起こるか:-

IF EXISTS (SELECT ....)
 BEGIN
  SELECT ... something
 END

ELSE
 BEGIN
  SELECT ... something else
 END

どのブランチを実行するかを事前に決定できない場合



1
SQL Serverは、ブランチを考慮せず、ブランチに含まれるステートメントのみを考慮するため、実行プランを再利用できます。
MartinC

回答:


10

SQL Serverは、ストアドプロシージャ内の条件分岐を無視することで、ストアドプロシージャのクエリプランのコンパイルプロセスを最適化します。計画は、最初の実行に使用されたパラメーターに基づいて生成されます。これは、ブランチでパラメーターが異なる場合に問題が発生します。

各ブランチのSQLを独自のストアドプロシージャに配置し、生成されたプランがそのブランチのパラメータの実際の使用に基づいているようにします。


6

唯一のショートカットは IF 1 = 1

@parameterとEXISTSの両方は、まだ「一般的なケース」(@parameter = 42たとえば)の処理を必要とします

それを言っています... 実際の実行計画は、再プロファイリングイベントをキャプチャするプロファイラと同様に何を言っていますか?(Jaoの回答によると、計画案は嫌いです)


3

実際ではなく、推定実行計画を表示してみてください。最初のCOND演算子には演算子が含まれていることがわかります。

この演算子は、キャッシュされた実行計画にも含まれていました。この例では、推定実行計画にCOND演算子が1つとSELECT分岐が2つ含まれるため、完全に再利用できます。バッチを実行すると、SQL ServerはDMLステートメントだけでなく他のすべてのステートメントも評価するため、それらを計画から取得します。

内部的に実行計画は、式ツリーに似た構造です。


0

計画は渡されたパラメーターに基づいて作成されるため、実際にはいいえと言います。通常はパラメーターに基づく条件付きロジックを使用しても、パフォーマンスに悪影響はありません。

パラメーターによってクエリオプティマイザーが気付くのに十分なばらつきがあると仮定すると、複数のプランが作成されます。

実行計画の表示をオンにしてスクリプトを実行することで、どれを確認できますか?計画の違いに注意してください。プロシージャを実行すると(ここではストアドプロシージャを想定しています)、初回の方が一般に高速であり、2回目のヒットではストアドプランが使用されます。パラメータを変更し、元のパラメータを繰り返し実行します-理論的にはプランはまだキャッシュ内にありますが、サーバーの使用状況に依存します(キャッシュティック-それらは永遠に残りません)。


0

2005年と2008年に改善されたかもしれませんが、2000年に条件を使用すると、説明よりも悪化する可能性が高く、プロシージャの最初の実行を最適に処理する計画をコンパイルし、条件がかわった。私の経験では、これにより、数分で実行されたクエリが数時間で実行されました。私は現在2008年を使用しており、2005年を使用していますが、それらを使用しなくなったため、そこでのコードの動作についてはコメントできません。


2
2005+ではステートメントレベルの再コンパイルが行われるため、「spごとに1つのプラン」はもうありません
-gbn
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.