Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Leistung von INNER JOIN und LEFT JOIN in SQL Server

Ein LEFT JOIN ist absolut nicht schneller als ein INNER JOIN . Tatsächlich ist es langsamer; Per Definition ist ein äußerer Join (LEFT JOIN oder RIGHT JOIN ) muss die ganze Arbeit eines INNER JOIN erledigen plus die zusätzliche Arbeit der Null-Erweiterung der Ergebnisse. Es wäre auch zu erwarten, dass mehr Zeilen zurückgegeben werden, was die Gesamtausführungszeit einfach aufgrund der größeren Größe der Ergebnismenge weiter verlängert.

(Und selbst wenn ein LEFT JOIN waren schneller in spezifisch Situationen aufgrund eines schwer vorstellbaren Zusammenflusses von Faktoren ist es funktionell nicht äquivalent zu einem INNER JOIN , Sie können also nicht einfach alle Instanzen des einen durch das andere ersetzen!)

Höchstwahrscheinlich liegen Ihre Leistungsprobleme woanders, z. B. wenn ein Kandidatenschlüssel oder ein Fremdschlüssel nicht richtig indiziert ist. 9 Tische sind ziemlich viel, also könnte die Verlangsamung buchstäblich fast überall sein. Wenn Sie Ihr Schema veröffentlichen, können wir möglicherweise weitere Details bereitstellen.

Bearbeiten:

Wenn ich weiter darüber nachdenke, könnte ich an einen Umstand denken, unter dem ein LEFT JOIN möglicherweise schneller als ein INNER JOIN , und das ist, wenn:

  • Einige der Tische sind sehr klein (z. B. unter 10 Zeilen);
  • Die Tabellen haben nicht genügend Indizes, um die Abfrage abzudecken.

Betrachten Sie dieses Beispiel:

CREATE TABLE #Test1
(
    ID int NOT NULL PRIMARY KEY,
    Name varchar(50) NOT NULL
)
INSERT #Test1 (ID, Name) VALUES (1, 'One')
INSERT #Test1 (ID, Name) VALUES (2, 'Two')
INSERT #Test1 (ID, Name) VALUES (3, 'Three')
INSERT #Test1 (ID, Name) VALUES (4, 'Four')
INSERT #Test1 (ID, Name) VALUES (5, 'Five')

CREATE TABLE #Test2
(
    ID int NOT NULL PRIMARY KEY,
    Name varchar(50) NOT NULL
)
INSERT #Test2 (ID, Name) VALUES (1, 'One')
INSERT #Test2 (ID, Name) VALUES (2, 'Two')
INSERT #Test2 (ID, Name) VALUES (3, 'Three')
INSERT #Test2 (ID, Name) VALUES (4, 'Four')
INSERT #Test2 (ID, Name) VALUES (5, 'Five')

SELECT *
FROM #Test1 t1
INNER JOIN #Test2 t2
ON t2.Name = t1.Name

SELECT *
FROM #Test1 t1
LEFT JOIN #Test2 t2
ON t2.Name = t1.Name

DROP TABLE #Test1
DROP TABLE #Test2

Wenn Sie dies ausführen und den Ausführungsplan anzeigen, sehen Sie, dass der INNER JOIN Die Abfrage kostet tatsächlich mehr als der LEFT JOIN , weil es die beiden oben genannten Kriterien erfüllt. Das liegt daran, dass SQL Server einen Hash-Abgleich für den INNER JOIN durchführen möchte , führt aber verschachtelte Schleifen für den LEFT JOIN aus; Ersteres ist normalerweise viel schneller, aber da die Anzahl der Zeilen so klein ist und Da kein Index verwendet werden kann, erweist sich die Hash-Operation als der teuerste Teil der Abfrage.

Sie können den gleichen Effekt sehen, indem Sie ein Programm in Ihrer bevorzugten Programmiersprache schreiben, um eine große Anzahl von Suchvorgängen in einer Liste mit 5 Elementen durchzuführen, im Vergleich zu einer Hash-Tabelle mit 5 Elementen. Aufgrund der Größe ist die Hashtabellenversion tatsächlich langsamer. Aber erhöhen Sie es auf 50 Elemente oder 5000 Elemente, und die Listenversion verlangsamt sich zu einem Crawling, weil es O(N) vs. O(1) für die Hashtabelle ist.

Aber ändern Sie diese Abfrage auf ID Spalte anstelle von Name und Sie werden eine ganz andere Geschichte sehen. In diesem Fall werden verschachtelte Schleifen für beide Abfragen ausgeführt, außer für den INNER JOIN Version ist in der Lage, einen der Clustered-Index-Scans durch eine Suche zu ersetzen - was bedeutet, dass dies buchstäblich eine Größenordnung sein wird schneller mit einer großen Anzahl von Zeilen.

Die Schlussfolgerung ist also mehr oder weniger das, was ich in mehreren Absätzen oben erwähnt habe; Dies ist mit ziemlicher Sicherheit ein Indizierungs- oder Indexabdeckungsproblem, möglicherweise in Kombination mit einer oder mehreren sehr kleinen Tabellen. Dies sind die einzigen Umstände, unter denen SQL Server möglicherweise wählen manchmal einen schlechteren Ausführungsplan für einen INNER JOIN als ein LEFT JOIN .