Gibt es eine bewährte Methode zwischen der Verwendung eines LEFT JOIN- oder eines NOT EXISTS-Formats?
Was bringt es, wenn man eins über das andere setzt?
Wenn keine, welche ist vorzuziehen?
SELECT *
FROM tableA A
LEFT JOIN tableB B
ON A.idx = B.idx
WHERE B.idx IS NULL
SELECT *
FROM tableA A
WHERE NOT EXISTS
(SELECT idx FROM tableB B WHERE B.idx = A.idx)
Ich verwende Abfragen in Access für eine SQL Server-Datenbank.
sql-server
join
exists
Michael Richardson
quelle
quelle
WHERE A.idx NOT IN (...)
ist nicht identisch aufgrund des dreiwertigen VerhaltenNULL
(dhNULL
nicht gleich istNULL
(noch ungleich), also , wenn Sie irgendwelcheNULL
intableB
unerwartete Ergebnisse erhalten!)Antworten:
Der größte Unterschied besteht nicht in der Verbindung vs nicht existiert, es ist (wie geschrieben), die
SELECT *
.Im ersten Beispiel erhalten Sie alle Spalten von beiden
A
undB
im zweiten Beispiel nur Spalten vonA
.In SQL Server ist die zweite Variante in einem sehr einfachen konstruierten Beispiel etwas schneller:
Erstellen Sie zwei Beispieltabellen:
Fügen Sie 10.000 Zeilen in jede Tabelle ein:
Entfernen Sie jede fünfte Zeile aus der zweiten Tabelle:
Führen Sie die beiden
SELECT
Testanweisungsvarianten durch:Ausführungspläne:
Die zweite Variante muss die Filteroperation nicht ausführen, da sie den linken Antisemi- Join-Operator verwenden kann.
quelle
Sie sind logischerweise identisch, liegen jedoch
NOT EXISTS
näher an dem von Ihnen gewünschten AntiSemiJoin und werden im Allgemeinen bevorzugt. Es wird auch besser hervorgehoben, dass Sie nicht auf die Spalten in B zugreifen können, da sie nur als Filter verwendet werden (im Gegensatz dazu, dass sie mit NULL-Werten verfügbar sind).Vor vielen Jahren (SQL Server 6.0 ish)
LEFT JOIN
war es schneller, aber das war lange nicht mehr der Fall. In diesen TagenNOT EXISTS
ist es etwas schneller.Die größte Auswirkung in Access besteht darin, dass die
JOIN
Methode den Join abschließen muss, bevor er gefiltert wird, um den verknüpften Satz im Speicher zu erstellen. Wenn SieNOT EXISTS
es verwenden, wird nach der Zeile gesucht, den Spalten wird jedoch kein Speicherplatz zugewiesen. Außerdem hört es auf zu suchen, sobald es eine Zeile findet. Die Leistung in Access variiert etwas stärker, aber eine allgemeine Faustregel lautet, dass die LeistungNOT EXISTS
tendenziell etwas schneller ist. Ich würde weniger geneigt sein zu sagen, dass es sich um "Best Practice" handelt, da es sich um mehr Faktoren handelt.quelle
Eine Ausnahme, die mir aufgefallen ist
NOT EXISTS
,LEFT JOIN ... WHERE IS NULL
ist die Verwendung von Verbindungsservern .Aus der Prüfung der Ausführungspläne geht hervor, dass der
NOT EXISTS
Operator in einer verschachtelten Schleife ausgeführt wird. Wobei es zeilenweise ausgeführt wird (was ich für sinnvoll halte).Beispielausführungsplan, der dieses Verhalten demonstriert:
quelle
INSERT INTO #t (a,b,c) SELECT a,b,c FROM LinkedServer.database.dbo.table WHERE x=y
dieNOT EXISTS (...)
Klausel mit dieser temporären Kopie der Datenbank ausgeführt wird.Im Allgemeinen erstellt die Engine einen Ausführungsplan, der im Wesentlichen auf folgenden Elementen basiert:
Für 4):
Der Plan "nicht vorhanden" empfiehlt einen Plan auf der Grundlage von Suchvorgängen für Tabelle B. Dies ist eine gute Wahl, wenn Tabelle A klein und Tabelle B groß ist (und ein Index für B vorhanden ist).
Der "Antijoin" -Plan ist eine gute Wahl, wenn Tabelle A sehr groß oder Tabelle B sehr klein oder kein Index für B ist und eine große Ergebnismenge zurückgibt.
Es ist jedoch nur eine "Ermutigung", wie eine gewichtete Eingabe. Ein starker (1), (2), (3) trifft oft die Wahl für (4) Moot.
(Ignorieren Sie die Auswirkung Ihres Beispiels, das aufgrund des von @MaxVernon angesprochenen * verschiedene Spalten zurückgibt.)
quelle