SQL Server INとEXISTSのパフォーマンス


115

以下のどれがより効率的であるか知りたいですか?

INSQL Serverは結果セットを大きなIFステートメントに変えると私は信じているので、私は常に使用に少し慎重でした。大きな結果セットの場合、これによりパフォーマンスが低下する可能性があります。小さな結果セットの場合、どちらが望ましいかわかりません。大きな結果セットの場合、EXISTSより効率的ではないでしょうか?

WHERE EXISTS (SELECT * FROM Base WHERE bx.BoxID = Base.BoxID AND [Rank] = 2)

WHERE bx.BoxID IN (SELECT BoxID FROM Base WHERE [Rank = 2])

8
見つける最良の方法は、それを試していくつかの測定を行うことです。
クラウスビスコフペダーセン

10
そこにいました ......このために無数の重複する
marc_s

5
@marc_s-おそらくそうですが、この件に関するすべての投稿を調べて、自分のケースに合う投稿を見つけるのに時間がかかったでしょう。質問に対して4つの答えがありました。
Randy Minder

7
参考までに、最もパフォーマンスの高い方法が必要な場合はselect 1 from Base...where exists実際には結果を気にせず、行が実際に存在するということだけを考慮してください。
ブラッド、2011

2
@marc_sは本当に悲しいです。スタックオーバーフローにゴミを追加しないようにするために、時間をかけて投稿を調べました。私は私の仕事を成し遂げるのに合わせた答えは必要ありません。それは、良い答えのあるほんの少しの代わりにGazillionの複製を追加したような考え方です
IvoC

回答:


140

EXISTS エンジンがヒットを見つけると、状態が真であることが証明されると、エンジンは見なくなります。

を使用するとIN、さらに処理する前にサブクエリからすべての結果を収集します。


4
それは良い点です。INステートメントでは、SQL Serverで完全な結果セットを生成してから、大きなIFステートメントを作成する必要があります。
Randy Minder、2010年

72
これは以前は真実でしたが、現在のバージョン(少なくとも2008年)では、オプティマイザーははるかにスマートです...実際には、IN()をEXISTS()と同じように扱います。
Aaron Bertrand

11
@Aaron-はい、通常、オプティマイザは内部でより良い計画を作成します。ただし、内部ショートカットに依存すると、より複雑なシナリオでは有害になる可能性があります。
スコットコーツ

2
これは単に間違っています。それは2010年であり、まだです。
マグナス

2
INとEXISTSはまったく同じクエリプランとIOを持っています。パフォーマンスが異なると考える理由はありません。あなたの時間統計をチェックして、自分自身を証明してください
Nelssen

40

受け入れられた答えは近視眼的であり、その点で質問は少し緩いです:

1)カバリングインデックスが左側にあるか、右側にあるか、または両側にあるかを明示的に述べていない。

2)どちらも入力左側セットと入力右側セットのサイズを考慮しません。
(質問は全体的に大きな結果セットについてのみ言及しています)。

(1)と(2)による大幅なコストの違いがある場合、オプティマイザは「in」と「exists」の間で変換できるほどスマートであると思います。それ以外の場合は、ヒントとしてのみ使用できます(たとえば、右側のシーク可能なインデックス)。

両方のフォームを内部で結合フォームに変換し、結合順序を逆にして、ループ、ハッシュ、またはマージとして実行することができます-推定された行数(左と右)および左、右、または両側のインデックスの存在に基づきます。


3
この優れた答えが注目されなくなった理由がわかりません。両側のインデックス/構造を理解することは、私が同意する影響を与える可能性があります。よく言った。
SheldonH 2015

オプティマイザは常に 同じ計画をINとに提供しEXISTSます。試してみて、彼らは同じ計画を得ることはありませんどのような場合を思い付く(これはには適用されませんがNOT INNOT EXISTS
マーティン・スミス

@MartinSmith私はあなたがあなたが話していることを知っていると思いますが、計画が常に同じであるという証拠はありますか?もしそうなら、ここで10年にわたる意見の相違を明らかにするでしょう。
MarredCheese

@MarredCheese-責任は、この単一の例を作成することが異なると主張する人々にあります
Martin Smith


5

非常に賛成されたものを含めて、ここには多くの誤解を招く答えがあります(私は彼らの操作が害を意味するとは信じていませんが)。簡単に言えば、これらは同じです。

(T-)SQL言語には多くのキーワードがありますが、結局、ハードウェアで実際に発生するのは、実行クエリプランに見られる操作のみです。

私たちが起動するときに我々が行うリレーショナル(数学理論)の操作[NOT] INおよび[NOT] EXISTS半(使用しているとき抗加入結合ですNOT)。対応するsql-server操作の名前が同じであることは偶然ではありません。言及しINたり、EXISTSどこにでもある操作はありません-(反)セミ結合のみです。このように、論理的に等価であること方法はありませんINEXISTS1との唯一の方法があるので選択がパフォーマンスに影響を与える可能性があり、(反)半、実行動作に参加し、その結果を得るためには

例:

クエリ1(計画

select * from dt where dt.customer in (select c.code from customer c where c.active=0)

クエリ2(計画

select * from dt where exists (select 1 from customer c where c.code=dt.customer and c.active=0)

あなたはそれをテストしましたか?その場合、SQLと結果を共有できますか?
UnhandledExcepSean 2018

複数回テストしました。別のテストケースを作成できますが、テストケースは、オプティマイザが統計が異なるテーブルでまったく同じ計画を実行することを意味しません。これは、誰かが答えを部分的であると考えるようにするかもしれません-しかし、複数の準結合演算子が存在しないのは事実です。たぶんどこかでリストを見つけてリンクします。
George Menoutis

5

INではなくEXISTSを使用します。以下のリンクを参照してください。

SQL Server:JOIN vs IN vs EXISTS-論理的な違い

返される結果に関して、INはEXISTSまたはJOINと同等に動作するという一般的な誤解があります。これは単に真実ではありません。

IN:指定された値がサブクエリまたはリストのいずれかの値と一致する場合にtrueを返します。

存在:サブクエリに行が含まれている場合はtrueを返します。

結合:結合列の2つの結果セットを結合します。

ブログのクレジット:https : //stackoverflow.com/users/31345/mladen-prajdic


うわー、ブログと説明ありがとうございます。
クリスチャンミュラー

3

これらの場合、実行プランは通常は同じになりますが、オプティマイザがインデックスなどの他のすべての要素をどのように考慮しているかを確認するまで、実際にはわかりません。


3

したがって、INはEXISTSと同じではなく、同じ実行プランを生成します。

通常、EXISTSは相関サブクエリで使用されます。つまり、EXISTS内部クエリを外部クエリと結合します。外部クエリ結合と内部クエリ結合を解決してから、それらのwhere句を一致させて両方を結合する必要があるため、結果を生成するためのステップが追加されます。

通常、INは内部クエリと外部クエリを関連付けずに使用されます。これは1つのステップでのみ解決できます(最良のシナリオ)。

このことを考慮:

  1. INを使用し、内部クエリの結果が数百万の異なる値の行である場合、EXISTSクエリのパフォーマンスが高い(外部クエリと結合するための適切なインデックスがある)ことを考えると、EXISTSよりも低速になります。

  2. EXISTSを使用し、外部クエリとの結合が複雑な場合(実行に時間がかかり、適切なインデックスがない場合)、外部テーブルの行数によってクエリが遅くなり、完了までの推定時間が数日になる場合があります。特定のハードウェアで行数が許容範囲内である場合、またはデータのカーディナリティが正しい場合(たとえば、大きなデータセットのDISTINCT値が少ない場合)、INはEXISTSよりも高速に実行できます。

  3. 上記のすべては、各テーブルにかなりの数の行がある場合に注意されます(つまり、CPU処理やキャッシュのRAMしきい値を超えるものを意味します)。

だから答えはそれが依存しています。INまたはEXISTS内に複雑なクエリを記述できますが、経験則として、限られた個別値のセットでINを使用し、個別値の多い行が多い場合はEXISTSを使用するようにしてください。

秘訣は、スキャンする行の数を制限することです。

よろしく、

マリアーノC


1

を最適化するにはEXISTS、非常にリテラルにします。何かが存在する必要がありますが、実際には、相関サブクエリから返されるデータは必要ありません。ブール条件を評価しているだけです。

そう:

WHERE EXISTS (SELECT TOP 1 1 FROM Base WHERE bx.BoxID = Base.BoxID AND [Rank] = 2)

相関サブクエリはRBARであるため、最初の結果ヒットで条件が真になり、それ以上処理されません。


LEFT JOIN + NULLコーディングの使用には常に非常に注意が必要です。NULLの取り扱いに細心の注意を払わないと、結果を見逃したり歪んだりする可能性が非常に高くなるからです。EXISTSまたはCTE(重複の検出、または欠落データの合成挿入)が同じ要件を満たしておらず、左結合+ NULL
Josh Lewis

3
TOP 1は、EXISTSと共に使用する場合、完全に無関係(またはイベント冗長)である必要があります。EXISTSは、一致する行が見つかるとすぐに戻ります。
Karl Kieninger、2015年

これまでのところ、このアプローチによるパフォーマンスの向上は見られませんでした。実行計画のスクリーンショットをいくつか見せてください
DaFi4 '20

-1

私の頭の上にあり、正しいことが保証されていません。この場合、2番目の方が速いと思います。

  1. 最初に、相関サブクエリにより、サブクエリが各行に対して実行される可能性があります。
  2. 2番目の例では、相関がないため、サブクエリは1回だけ実行する必要があります。
  3. 2番目の例INでは、一致が見つかるとすぐにが短絡します。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.