LEFT JOIN vs. NOT IN vs. NOT EXISTS

In diesem Beitrag gehe ich der Frage nach wie bekommt man mit SQL die Datensätze einer Tabelle, die nicht mit einem Datensatz einer anderen Tabelle Verknüpft sind.

Die Tabellenstruktur und Werte für die Beispiel-SQL-Abfrage sieht dabei wie folgt aus:

Datentabelle: tabelle1
IDt1
1
2
3
4
Datentabelle: tabelle2
Wertt2IDt1
1011
1022
103NULL (1)
NULL4

Gesucht ist also der Datensatz der Tabelle tabelle1 mit dem IDt1-Wert 3.

LEFT JOIN SQL-Query

Mittels eines JOINs können die beiden Tabellen über den Wert IDt1 mit einander verknüpft werden. Dabei sollen auch Datensätze aus tabelle1 berücksichtigt werden, die mit keinem Datensatz in tabelle2 verknüpft sind. Es wird daher ein LEFT JOIN verwendet. Die Abfrage ist dann noch auf die Datensätze zu beschränken, für die in der tabelle2 kein IDt1-Wert vorhanden ist, d.h. NULL ist.

Die SQL-Abfrage unter Verwendung eine LEFT JOIN lautet somit:

SQL-Abfrage:
  1. SELECT t1.IDt1
  2. FROM tabelle1 AS t1
  3. LEFT JOIN tabelle2 AS t2 ON t2.IDt1 = t1.IDt1
  4. WHERE t2.IDt1 IS NULL

Als Ergebnis dieser Abfrage erhält man einen Datensatz, den mit dem IDt1-Wert gleich 3.

 

NOT IN SQL-Query

Die zweite Möglichkeit ist alle IDt1-Werte in tabelle2 in einem Subquery zu ermitteln. Im Query dann mittels NOT IN alle IDt1-Werte aus tabelle1 zu ermitteln, die nicht im Subquery vorhanden sind.

Zu beachten ist das Verhalten des IN-Operators. Dieser kann drei Werte zurückliefern: true, NULL, false

True wird ausgegeben, wenn die Unterabfrage einen Wert ungleich NULL enthält. Ist kein Wert ungleich NULL und kein NULL-Wert vorhanden, so ist der Rückgabewert false. Ist ein NULL in den Ergebnissen des Subqueries vorhanden so wird ein NULL zurückgeliefert. Mit der Negierung NOT wird true und false vertauscht, der Rückgabewert NULL bleibt aber NULL.

Da für die benötigt Query aber ein true oder false als Rückgabewert zwingend erfordert wird, muss das Vorhandensein eines NULL-Wertes im Subquery ausgeschlossen werden. Entweder muss dies von der Datentabellen-Struktur her sichergestellt sein – ist in diesem Beispiel nicht der Fall (1) – oder es muss in der SQL-Abfrage berücksichtigt werden.

Die SQL-Abfrage unter Verwendung des NOT IN lautet somit:

SQL-Abfrage:
  1. SELECT t1.IDt1
  2. FROM tabelle1 AS t1
  3. WHERE t1.IDt1 NOT IN
  4.  (
  5.   SELECT t2.IDt1
  6.   FROM tabelle2 AS t2
  7.   WHERE t2.IDt1 IS NOT NULL
  8.  )

Als Ergebnis dieser Abfrage erhält man einen Datensatz, den mit dem IDt1-Wert gleich 3.

 

NOT EXISTS SQL-Query

NOT EXISTS ist eine weitere Möglichkeit die gesuchten Datensätze zu ermitteln. In einem Subquery werden die passenden Datensätze in tabelle2 ermittelt. Der Einfachheit halber wird nur eine 1 in die Ergebnisliste aufgenommen und nicht ein Wert aus dem Datensatz, da kein spezifischer Wert benötigt wird. Da EXISTS im Unterschied zu IN nur true oder false zurückliefert muss hier keine NULL-Werte ausgeschlossen werden. Existiert im Subquery kein passender Datensatz so wird der Datensatz aus tabelle1 ausgegeben.

Die SQL-Abfrage unter Verwendung des NOT IN lautet somit:

SQL-Abfrage:
  1. SELECT t1.IDt1
  2. FROM tabelle1 AS t1
  3. WHERE NOT EXISTS
  4.  (
  5.   SELECT 1
  6.   FROM tabelle2 AS t2
  7.   WHERE t2.IDt1 = t1.IDt1
  8.  )

Als Ergebnis dieser Abfrage erhält man einen Datensatz, den mit dem IDt1-Wert gleich 3.

 

Wenn alle drei SQL-Abfragen das gleiche Ergebnis liefern, dann stellt sich die Frage welches Query man nutzen sollte.

Um diese Frage zu beantworten habe ich beide Datentabellen mit je 50.000 Datensätzen gefüllt. Dann habe ich aller drei SQL-Abfragen ausgeführt und verglichen wie lange die einzelnen Abfragen dauerten. Zudem habe ich die Anzahl der Datensätze, die als Ergebnis zurückgeliefert werden variiert.

Die Variante mit NOT EXISTS liefert am schnellsten ein Ergebnis. Das NOT IN-Query ist etwas langsamer. Im Schnitt benötigt es 1,2-mal so lange wie die NOT EXISTS-Abfrage. Die LEFT JOIN-Variante ist die langsamste Lösung. Sie benötigt immer mehr als doppelt so lange wie die NOT EXISTS-Abfrage bis das Ergebnis der Abfrage feststeht.

Stellt man sicher, dass in der Datentabelle kein NULL-Wert vorkommt, so kann man die WHERE-Klausel bei der NOT IN-Abfrage (Zeile 7) weglassen. Dies hat zur Folge, dass die Ausführungszeit dann praktisch identisch mit der der NOT EXISTS-Abfrage ist.

Die NOT EXISTS-Variante ist die schnellste der drei Varianten.

 

Kommentare anzeigenSeite kommentieren
Laden...Kommentare werden geladen.
Laden...Formular zum Schreiben eines Kommentars wird geladen.


 

Google+
Facebook
Pin it
Twitter
Blogger
Google Mail
E-Mail schreiben