web-dev-qa-db-ja.com

SQL Serverにクエリ条件を記述どおりに実行させますか?

SQL Server 2008 R2を使用していて、次の疑似クエリ(SP)があります。

select ...
from ...
WHERE    @LinkMode IS NULL
     AND (myColumn IN (...very long-running query...))
     ...
     ...

問題は、SP with @LinkMode=2。を実行しても、クエリの実行に非常に長い時間がかかることです。

お気づきのように、長期実行クエリは@LinkModeがnullの場合にのみ実行する必要がありますが、ここではそうではありません。私の場合、@ LinkMode = 2!

ただし、次のように変更した場合:

 select ...
    from ...
    WHERE    1=2
         AND (myColumn IN (...very long time exeted query...))
     ...
     ...

SP does高速に実行します。

以前に、オプティマイザが基準の順序を最適化できることがあると聞いたことがあります。

だから私は尋ねます:

  • オプティマイザが別のルートを選択した場合でも、=nullかどうかを確認するよりも高速な方法はありますか?つまり、if a==nullのチェックははるか他の長いクエリを実行するよりも高速だと思います...

  • SQL Serverでクエリをforce実行して、作成したとおりにクエリを実行するにはどうすればよいですか(同じ順序)?

14
Royi Namir

"Catch-All Query"トラップに陥っています。これは Gail Shaw here によって非常によく説明されています。

問題を要約すると、SQL Serverは、コンパイル後にクエリプランをキャッシュし、後でコンパイルする前に、一致するクエリプランのキャッシュをチェックすることにより、クエリコンパイルの大きなオーバーヘッドを最適化します。ここで発生する「マッチング」は純粋にテキストによるものであるため、変数の実際の値はこれに影響しません。

それはgoodの時間の99%ですが、場合によってはbadです。それが悪い1つのケースは、誰かがWHERE句をCでの短絡IF文のように構築しようとするときです。SQLコンパイラはoneパラメータ値が実際に何であるかに関係なく機能するクエリプラン、およびこれらの「賢い」論理スイッチング条件を処理できる唯一の方法WHERE句は、インデックスを利用せずに、テーブル全体をスキャンして行をフィルタリングするだけの単純な総当たりプランを作成することです。

当然のことながら、これにより、パラメーター/変数の値に関係なく、これらの速度が均一に遅くなります。

22
RBarryYoung

SQLサーバーに特定の順序で句の条件を強制的に実行させる保証された方法はありません。オプティマイザは常に、適切と思われる順序でそれらを評価します。

あなたができることは次のようなものです:

IF @LinkMode IS NULL
BEGIN
    select ...
    from ...
    WHERE (myColumn IN (...very long time exeted query...))
         ...
         ...
END
ELSE
BEGIN
    select ...
    from ...
    WHERE ...
         ...
END

オプションの場合は、IFステートメントを使用して適切な形式のクエリを実行します。また、SQLでは、どのようにすべきかではなく、何をすべきかをdbエンジンに指示します-物事は最初から最後まで実行されません。それが何をするかを正確に予測することは難しい場合があります。あなたはおそらくこれを知っているでしょう;)

3
Sam

動的SQLもおそらく機能します。その場合、クエリオプティマイザーは実行時に実際の値を取得する必要があるためです(私が間違っている場合は修正してください。実際はわかりませんが、同様の状況で使用することを覚えておいてください)。しかし、IF/ELSE句が必要なものを正確に実行する最も単純で最も簡単なソリューションであるため、IF/ELSE句が最も効果的であるという点で、私は他の人と一緒にいます。

まだ使用していない場合に備えて、今後の参考のために、動的SQLの実際の使用例が掲載された恐ろしい醜いサイトがここにあります: http://sqlusa.com/bestpractices/dynamicsql/

2
Kahn

IF/ELSE構文をお勧めします。何らかの理由で機能しない場合は、WITH RECOMPILEオプションの使用をいつでも検討できます。

1
timvw