Was ist der Unterschied zwischen NOT EXISTS vs. NOT IN vs. LEFT JOIN WHERE IS NULL?

151

Es scheint mir, dass Sie dasselbe in einer SQL-Abfrage tun können, indem Sie entweder NOT EXISTS, NOT IN oder LEFT JOIN WHERE IS NULL verwenden. Beispielsweise:

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

Ich bin nicht sicher, ob ich die gesamte Syntax richtig verstanden habe, aber dies sind die allgemeinen Techniken, die ich gesehen habe. Warum sollte ich mich dafür entscheiden, eins über das andere zu verwenden? Unterscheidet sich die Leistung ...? Welches davon ist das schnellste / effizienteste? (Wenn es von der Implementierung abhängt, wann würde ich jeden verwenden?)

froadie
quelle
6
Viele gängige SQL-Engines bieten Ihnen die Möglichkeit, einen Ausführungsplan anzuzeigen. Auf diese Weise können Sie häufig erhebliche Effizienzunterschiede bei logisch äquivalenten Abfragen feststellen. Der Erfolg einer Methode hängt von Faktoren wie der Tabellengröße, den vorhandenen Indizes und anderen ab.
Chris Farmer
2
@wich: Keine Datenbank kümmert sich darum, was genau Sie innerhalb der EXISTSKlausel zurückgeben. Sie können zurückkehren *, NULLoder was auch immer: alles wird optimiert entfernt werden.
Quassnoi
2
@wich - warum? Beide hier: techonthenet.com/sql/exists.php und hier: msdn.microsoft.com/en-us/library/ms188336.aspx scheinen * ...
froadie
8
@wich: Hier geht es nicht darum, "Interesse auszudrücken". Hier geht es um den Abfrage-Parser, der Sie auffordert, etwas zwischen SELECTund zu setzen FROM. Und *ist einfach einfacher zu tippen. Ja, SQLhat Ähnlichkeit mit einer natürlichen Sprache, aber sie wird von einer Maschine, einer programmierten Maschine, analysiert und ausgeführt. Es ist nicht so, dass es jemals plötzlich in Ihre Kabine eindringen wird und " EXISTSHör auf, nach den zusätzlichen Feldern in einer Abfrage zu fragen, weil ich es satt habe, sie zu analysieren und sie dann wegzuwerfen!". Mit einem Computer ist das wirklich in Ordnung.
Quassnoi
1
@Quassnoi Wenn Sie Code für den alleinigen Zweck einer Maschine geschrieben hätten, die ihn interpretiert, würde der Code schrecklich aussehen, und leider arbeiten einige Leute so. Wenn Sie jedoch Code in einer anderen Optik schreiben und Code schreiben, um auszudrücken, was die Maschine als Mitteilung an Ihre Kollegen tun soll, schreiben Sie besseren und wartbareren Code. Seien Sie schlau, schreiben Sie Code für Menschen, nicht für den Computer.
Weicht

Antworten:

139

In einer Nussschale:

NOT INist ein bisschen anders: Es stimmt nie überein, wenn es nur eine einzige NULLin der Liste gibt.

  • In MySQL, NOT EXISTSist ein bisschen weniger effizient

  • In SQL Server, LEFT JOIN / IS NULList weniger effizient

  • In PostgreSQL, NOT INist weniger effizient

  • In Oraclesind alle drei Methoden gleich.

Quassnoi
quelle
1
Danke für die Links! Und danke für die schnelle Übersicht ... Mein Büro blockiert den Link aus irgendeinem Grund: P, aber ich werde es überprüfen, sobald ich an einen normalen Computer komme.
Froadie
2
Ein weiterer Punkt ist, dass wenn die Abfrage table1 .aenthält, diese Zeile nicht zurückgegeben wird, die Abfrage jedoch leer ist. NOT IN vs. NOT EXISTS Nullable Columns: SQL ServerNULLEXISTSNOT INtable2
Martin Smith
@ MartinSmith: wird NULL NOT IN ()als wahr (nicht NULL) ausgewertet , genau wieNOT EXISTS (NULL = column)
Quassnoi
2
@ Quassnoi - er, guter Punkt, habe das falsch herum verstanden. Der NOT EXISTSgibt die Zeile immer zurück, NOT INtut dies jedoch nur, wenn die Unterabfrage keine Zeilen zurückgibt.
Martin Smith
5

Wenn die Datenbank die Abfrage gut optimieren kann, werden die beiden ersten in etwas nahe der dritten umgewandelt.

Für einfache Situationen wie die in Ihrer Frage sollte es keinen oder nur einen geringen Unterschied geben, da alle als Joins ausgeführt werden. Bei komplexeren Abfragen kann die Datenbank möglicherweise keinen Join aus den Abfragen not inund not existserstellen. In diesem Fall werden die Abfragen viel langsamer. Auf der anderen Seite kann ein Join auch eine schlechte Leistung erbringen, wenn kein Index verwendet werden kann. Nur weil Sie einen Join verwenden, bedeutet dies nicht, dass Sie sicher sind. Sie müssten den Ausführungsplan der Abfrage überprüfen, um festzustellen, ob möglicherweise Leistungsprobleme vorliegen.

Guffa
quelle
2

Angenommen, Sie vermeiden Nullen, dann sind dies alle Möglichkeiten, einen Anti-Join zu schreiben mit Standard SQL zu .

Eine offensichtliche Auslassung ist das Äquivalent mit EXCEPT:

SELECT a FROM table1
EXCEPT
SELECT a FROM table2

Hinweis: In Oracle müssen Sie den MINUSOperator verwenden (wahrscheinlich ein besserer Name):

SELECT a FROM table1
MINUS
SELECT a FROM table2

Apropos proprietäre Syntax: Abhängig von dem Produkt, das Sie verwenden, z. B. OUTER APPLYin SQL Server (etwa) , gibt es möglicherweise auch Nicht-Standard-Äquivalente, die untersucht werden sollten :

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;
eines Tages, wenn
quelle
0

Wenn Sie Daten in eine Tabelle mit einem Primärschlüssel mit mehreren Feldern einfügen müssen, denken Sie daran, dass es viel schneller sein wird (ich habe in Access versucht, aber ich denke in jeder Datenbank), nicht zu überprüfen, ob "keine Datensätze mit 'solchen' Werten in der Tabelle vorhanden sind". - lieber einfach in die Tabelle einfügen, und überschüssige Datensätze (mit dem Schlüssel) werden nicht zweimal eingefügt.

Baleks
quelle
0

In der Leistungsperspektive wird immer die Verwendung inverser Schlüsselwörter wie NOT IN, NOT EXISTS, ... vermieden. Um die inversen Elemente zu überprüfen, muss DBMS alle verfügbaren Elemente durchlaufen und die inverse Auswahl löschen.

Lahiru Cooray
quelle
1
Und was schlagen Sie als Problemumgehung vor, wenn Sie es tatsächlich benötigen NOT?
dnoeth
Nun, wenn es keine Möglichkeit gibt, müssen wir NOT-Operationen verwenden, und deshalb gibt es sie. Best Practice ist, sie zu vermeiden, wenn wir andere alternative Lösungen haben.
Lahiru Cooray
@onedaywhen, wenn ein Optimierer eine Abfrage transformiert und das falsche Ergebnis zurückgibt, dann ist es ein Fehler
David דודו Markovitz
@DuduMarkovitz: Ja, und wenn Sie sich an das SQL Server-Team wenden und dieser den Fehler erkennt, sich jedoch weigert, ihn zu beheben, weil er sagt, dass dies dazu führen kann, dass Abfragen langsamer ausgeführt werden, ist dies ein Fehler, mit dem Sie sich befassen müssen .
Tag, wenn
@onedaywhen - Dies war vermutlich kein hypothetisches Szenario :-) Erinnerst du dich zufällig an die Fehlerdetails?
David Markovitz