NOT EXISTS対NOT IN対LEFT JOIN WHERE IS NULLの違いは何ですか?


151

NOT EXISTS、NOT IN、またはLEFT JOIN WHERE IS NULLのいずれかを使用してSQLクエリで同じことができるように思えます。例えば:

SELECT a FROM table1 WHERE a NOT IN (SELECT a FROM table2)

SELECT a FROM table1 WHERE NOT EXISTS (SELECT * FROM table2 WHERE table1.a = table2.a)

SELECT a FROM table1 LEFT JOIN table2 ON table1.a = table2.a WHERE table1.a IS NULL

すべての構文が正しいかどうかはわかりませんが、これらは私が見た一般的な手法です。なぜどちらか一方を使用することを選択するのですか?パフォーマンスは異なりますか?これらのうちどれが最も速く/最も効率的ですか?(実装に依存する場合、それぞれをいつ使用しますか?)


6
多くの一般的なSQLエンジンでは、実行プランを確認できます。このようにして、論理的に同等なクエリの効率の大きな違いを見つけることができます。どの方法が成功するかは、テーブルサイズ、存在するインデックスなどの要因に依存します。
Chris Farmer

2
@wich:EXISTS句内で正確に何が返されるかを気にするデータベースはありません。あなたは返すことがあり*NULLまたは任意:これはすべて離れて最適化されます。
Quassnoi、2010

2
@wich-なぜですか?ここでは両方:techonthenet.com/sql/exists.phpとここでは:msdn.microsoft.com/en-us/library/ms188336.aspxが* ...を使用しているようです
froadie

8
@wich:これは「関心を表現する」ことではありません。これは、SELECTとの間に何かを置くことを要求するクエリパーサーに関するものFROMです。そして*、単にタイプするのが簡単です。はい、SQL自然言語に似ていますが、プログラム化されたマシンによって解析および実行されます。それは突然あなたのキュービクルに突然侵入して、「EXISTSクエリで追加のフィールドを要求するのをやめるので、それらを解析して捨てるのにうんざりしている!」と叫ぶということではありません。本当に、コンピューターで大丈夫です。
Quassnoi、2010

1
@Quassnoiあなたがそれを解釈するマシンの唯一の目的のためにコードを書いたなら、コードは恐ろしく見えるでしょう、そして残念ながらかなりの数の人々がそのように働いています。ただし、別の光学系でコードを記述したり、ピアにコミュニケとしてマシンに実行させたいことを表現するコードを記述したりすると、より優れた、より保守しやすいコードが記述されます。賢く、コンピュータではなく、人のためにコードを書いてください。
ウィッヒ

回答:


139

一言で言えば:

NOT INは少し異なりNULLます。リストに1つしかない場合は一致しません。

  • ではMySQLNOT EXISTS少し効率が悪い

  • ではSQL ServerLEFT JOIN / IS NULL効率が悪い

  • ではPostgreSQLNOT IN効率が悪い

  • ではOracle、3つの方法はすべて同じです。


1
リンクをありがとう!簡単な概要に感謝します...私のオフィスは何らかの理由でリンクをブロックしています:Pが、通常のコンピューターに到達したらすぐにチェックアウトします。
froadie

2
別のポイントは、クエリがtable1 .a含まれNULLている場合、EXISTSこの行は返されませんが、NOT INクエリtable2が空の場合は返されるということです。NOT IN vs. NOT EXISTS Nullable Columns:SQL Server
Martin Smith

@MartinSmith:NULL NOT IN ()同様にtrueに評価されます(ではありませんNULLNOT EXISTS (NULL = column)
Quassnoi '19年

2
@Quassnoi-ええと、良い点ですが、それは間違った方法です。NOT EXISTS常に行が返されますが、NOT INサブクエリが行を戻さない場合にのみ、そうします。
マーティンスミス

5

データベースがクエリの最適化に優れている場合、最初の2つは3番目に近いものに変換されます。

質問のような単純な状況の場合、それらはすべて結合として実行されるため、ほとんどまたはまったく違いがないはずです。より複雑なクエリでは、データベースがnot inand not existsクエリから結合できない場合があります。その場合、クエリは非常に遅くなります。一方、使用できるインデックスがない場合、結合のパフォーマンスも低下することがあります。そのため、結合を使用したからといって、安全であるとは限りません。クエリの実行プランを調べて、パフォーマンスの問題があるかどうかを確認する必要があります。


2

nullを回避していると仮定すると、nullはすべて、標準SQLを使用して反結合を作成する方法です。

明らかな省略は、以下を使用した場合と同等EXCEPTです。

SELECT a FROM table1
EXCEPT
SELECT a FROM table2

Oracleでは、MINUS演算子(おそらくより適切な名前)を使用する必要があることに注意してください。

SELECT a FROM table1
MINUS
SELECT a FROM table2

独自仕様の構文といえば、たとえばOUTER APPLYSQL Serverで使用している製品(など)によっては、調査する価値のある非標準の同等のものもある場合があります。

SELECT t1.a
  FROM table1 t1
       OUTER APPLY 
       (
        SELECT t2.a
          FROM table2 t2
         WHERE t2.a = t1.a
       ) AS dt1
 WHERE dt1.a IS NULL;

0

複数フィールドの主キーを持つテーブルにデータを挿入する必要がある場合は、「Accessで試したが、どのデータベースでも考える)「テーブルに「そのような」値を持つレコードが存在しない」ことを確認しない方がはるかに高速であることを考慮してください。 -テーブルに挿入するだけで、余分なレコード(キーによる)は2回挿入されません。


0

パフォーマンスの観点では、NOT IN、NOT EXISTSなどのインバースキーワードの使用は常に避けてください。インバースアイテムをチェックするには、DBMSが利用可能なすべてのアイテムを実行し、インバース選択を削除する必要があるためです。


1
そして、実際に必要な場合の回避策として何を提案しますNOTか?
dnoeth

原因のオプションがない場合は、NOT演算を使用する必要があり、それが存在する理由です。他の代替ソリューションがある場合は、回避することをお勧めします。
Lahiru Cooray 2016年

@onedaywhen、オプティマイザがクエリを変換して誤った結果を返す場合、それはバグです
David David Markovitz

@DuduMarkovitz:はい、SQL Serverチームに連絡してバグを認めても、クエリの実行が遅くなる可能性があるとの理由で修正を拒否した場合、対処する必要のあるバグです
onedaywhen

@onedaywhen-これは、私が想定している架空のシナリオではありませんでした:-)バグの詳細を覚えていますか?
DavidדודוMarkovitz
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.