web-dev-qa-db-ja.com

T-SQLでIFを使用すると、実行プランのキャッシュが弱まったり壊れたりしますか?

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

どのブランチが実行されるかを事前に決定できない場合は?

20
AnthonyWJones

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

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

10
MartinC

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

@parameterとEXISTSはどちらも、「一般的なケース」(@parameter = 42 いう)

それを言って... actual実行プランは何を言っているのか、プロファイラーは再コンパイルイベントをキャプチャしていますか? (私はJaoの答えによる推定計画が嫌いです)

6
gbn

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

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

内部的には、実行プランは式ツリーに似た構造です。

3
Jao

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

パラメータによってクエリオプティマイザが気付くほどの差異が生じると想定すると、複数のプランが生成されます。

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

0
Barry King

多分それは2005年と2008年に改善されましたが、2000年に条件文を使用することはあなたが説明するより悪い可能性が高いです、それは手順の最初の実行を最もよく処理するために計画をコンパイルし、それから条件があったときでもその計画を使用して手順を実行しますかわった。私の経験では、これにより、数分で実行されるクエリが数時間で実行されました。私は2008年を使用していて、2005年を使用していますが、私はそれらをもはや使用していないので、そこでの調剤の働きについてコメントすることはできません。

0
tom evers