Ich habe einen SQL-Befehl erstellt, der INNER JOIN für 9 Tabellen verwendet. Dieser Befehl dauert jedoch sehr lange (mehr als fünf Minuten). Mein Volk schlug mir daher vor, INNER JOIN in LEFT JOIN zu ändern, da die Leistung von LEFT JOIN trotz meiner Kenntnisse besser ist. Nachdem ich es geändert hatte, wurde die Abfragegeschwindigkeit erheblich verbessert.
Ich würde gerne wissen, warum LEFT JOIN schneller ist als INNER JOIN?
Mein SQL-Befehl sieht wie folgt aus:
SELECT * FROM A INNER JOIN B ON ... INNER JOIN C ON ... INNER JOIN D
und so weiter
Update: Dies ist eine kurze Beschreibung meines Schemas.
FROM sidisaleshdrmly a -- NOT HAVE PK AND FK
INNER JOIN sidisalesdetmly b -- THIS TABLE ALSO HAVE NO PK AND FK
ON a.CompanyCd = b.CompanyCd
AND a.SPRNo = b.SPRNo
AND a.SuffixNo = b.SuffixNo
AND a.dnno = b.dnno
INNER JOIN exFSlipDet h -- PK = CompanyCd, FSlipNo, FSlipSuffix, FSlipLine
ON a.CompanyCd = h.CompanyCd
AND a.sprno = h.AcctSPRNo
INNER JOIN exFSlipHdr c -- PK = CompanyCd, FSlipNo, FSlipSuffix
ON c.CompanyCd = h.CompanyCd
AND c.FSlipNo = h.FSlipNo
AND c.FSlipSuffix = h.FSlipSuffix
INNER JOIN coMappingExpParty d -- NO PK AND FK
ON c.CompanyCd = d.CompanyCd
AND c.CountryCd = d.CountryCd
INNER JOIN coProduct e -- PK = CompanyCd, ProductSalesCd
ON b.CompanyCd = e.CompanyCd
AND b.ProductSalesCd = e.ProductSalesCd
LEFT JOIN coUOM i -- PK = UOMId
ON h.UOMId = i.UOMId
INNER JOIN coProductOldInformation j -- PK = CompanyCd, BFStatus, SpecCd
ON a.CompanyCd = j.CompanyCd
AND b.BFStatus = j.BFStatus
AND b.ProductSalesCd = j.ProductSalesCd
INNER JOIN coProductGroup1 g1 -- PK = CompanyCd, ProductCategoryCd, UsedDepartment, ProductGroup1Cd
ON e.ProductGroup1Cd = g1.ProductGroup1Cd
INNER JOIN coProductGroup2 g2 -- PK = CompanyCd, ProductCategoryCd, UsedDepartment, ProductGroup2Cd
ON e.ProductGroup1Cd = g2.ProductGroup1Cd
sql
sql-server
performance
Anonym
quelle
quelle
coUOM
? Wenn nicht, können Sie möglicherweise einen Semi-Join verwenden. Wenn ja, können SieUNION
als Alternative verwenden. Nur IhreFROM
Klausel zu veröffentlichen, ist hier eine unzureichende Information.Antworten:
A
LEFT JOIN
ist absolut nicht schneller als aINNER JOIN
. In der Tat ist es langsamer; Per Definition muss ein Outer Join (LEFT JOIN
oderRIGHT JOIN
) die gesamte Arbeit einesINNER JOIN
Plus erledigen, zusätzlich die zusätzliche Arbeit, die Ergebnisse auf Null zu erweitern. Es wird auch erwartet, dass mehr Zeilen zurückgegeben werden, was die Gesamtausführungszeit allein aufgrund der größeren Größe der Ergebnismenge weiter erhöht.(Und selbst wenn ein
LEFT JOIN
waren schneller in bestimmten Situationen aufgrund einiger schwer denken Zusammenfluß von Faktoren ist es nicht funktional äquivalent zu einemINNER JOIN
, so dass Sie nicht einfach alle Instanzen eine mit dem anderen zu ersetzen gehen kann!)Höchstwahrscheinlich liegen Ihre Leistungsprobleme an anderer Stelle, z. B. wenn ein Kandidatenschlüssel oder ein Fremdschlüssel nicht ordnungsgemäß indiziert ist. 9 Tische sind ziemlich viel zu verbinden, so dass die Verlangsamung buchstäblich fast überall sein könnte. Wenn Sie Ihr Schema veröffentlichen, können wir möglicherweise weitere Details bereitstellen.
Bearbeiten:
Wenn ich weiter darüber nachdenke, könnte ich mir einen Umstand vorstellen, unter dem a
LEFT JOIN
schneller sein könnte als aINNER JOIN
, und dann:Betrachten Sie dieses Beispiel:
Wenn Sie dies ausführen und den Ausführungsplan anzeigen, werden Sie feststellen, dass die
INNER JOIN
Abfrage tatsächlich mehr kostet als dieLEFT JOIN
, da sie die beiden oben genannten Kriterien erfüllt. Dies liegt daran, dass SQL Server eine Hash-Übereinstimmung für die durchführen möchteINNER JOIN
, jedoch verschachtelte Schleifen für dieLEFT JOIN
; Ersteres ist normalerweise viel schneller, aber da die Anzahl der Zeilen so gering ist und kein Index verwendet werden kann, stellt sich heraus, dass die Hashing-Operation der teuerste Teil der Abfrage ist.Sie können den gleichen Effekt erzielen, 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 Hash-Tabellenversion tatsächlich langsamer. Erhöhen Sie es jedoch auf 50 Elemente oder 5000 Elemente, und die Listenversion verlangsamt sich zu einem Crawl, da es für die Hashtabelle O (N) vs. O (1) ist.
Wenn Sie diese Abfrage jedoch so ändern, dass sie sich in der
ID
Spalte statt befindetName
, wird eine ganz andere Geschichte angezeigt. In diesem Fall werden verschachtelte Schleifen für beide Abfragen ausgeführt, aber dieINNER JOIN
Version kann einen der Clustered-Index-Scans durch eine Suche ersetzen. Dies bedeutet, dass dies bei einer großen Anzahl von Zeilen buchstäblich eine Größenordnung schneller ist.Die Schlussfolgerung ist also mehr oder weniger das, was ich oben in mehreren Absätzen erwähnt habe. Dies ist mit ziemlicher Sicherheit ein Indexierungs- oder Indexabdeckungsproblem, möglicherweise kombiniert mit einer oder mehreren sehr kleinen Tabellen. Das sind die einzigen Umstände , unter denen SQL Server können manchmal einen schlechteren Ausführungsplan für einen wählen
INNER JOIN
als einLEFT JOIN
.quelle
Es gibt ein wichtiges Szenario, das dazu führen kann, dass ein äußerer Join schneller ist als ein innerer Join, der noch nicht besprochen wurde.
Bei Verwendung eines äußeren Joins kann der Optimierer die äußere verknüpfte Tabelle immer aus dem Ausführungsplan löschen, wenn die Join-Spalten die PK der äußeren Tabelle sind und keine der äußeren Tabellenspalten außerhalb des äußeren Joins selbst referenziert wird. Beispiel:
SELECT A.* FROM A LEFT OUTER JOIN B ON A.KEY=B.KEY
B.KEY ist die PK für B. Sowohl Oracle (ich glaube, ich habe Release 10 verwendet) als auch SQL Server (ich habe 2008 R2 verwendet) bereinigen Tabelle B aus dem Ausführungsplan.Dasselbe gilt nicht unbedingt für einen inneren Join:
SELECT A.* FROM A INNER JOIN B ON A.KEY=B.KEY
Abhängig von den vorhandenen Einschränkungen kann B im Ausführungsplan erforderlich sein oder nicht.Wenn A.KEY ein nullbarer Fremdschlüssel ist, der auf B.KEY verweist, kann der Optimierer B nicht aus dem Plan entfernen, da er bestätigen muss, dass für jede A-Zeile eine B-Zeile vorhanden ist.
Wenn A.KEY ein obligatorischer Fremdschlüssel ist, der auf B.KEY verweist, kann der Optimierer B aus dem Plan entfernen, da die Einschränkungen die Existenz der Zeile garantieren. Nur weil der Optimierer die Tabelle aus dem Plan entfernen kann, heißt das nicht, dass dies der Fall ist. SQL Server 2008 R2 löscht B NICHT aus dem Plan. Oracle 10 löscht B aus dem Plan. In diesem Fall ist leicht zu erkennen, wie der äußere Join den inneren Join auf SQL Server übertrifft.
Dies ist ein triviales Beispiel und für eine eigenständige Abfrage nicht praktikabel. Warum an einen Tisch gehen, wenn Sie nicht müssen?
Dies könnte jedoch eine sehr wichtige Entwurfsüberlegung beim Entwerfen von Ansichten sein. Häufig wird eine "Alles-tun" -Ansicht erstellt, die alles zusammenfügt, was ein Benutzer möglicherweise in Bezug auf eine zentrale Tabelle benötigt. (Insbesondere, wenn naive Benutzer Ad-hoc-Abfragen ausführen, die das relationale Modell nicht verstehen.) Die Ansicht enthält möglicherweise alle relevanten Spalten aus vielen Tabellen. Die Endbenutzer greifen jedoch möglicherweise nur über eine Teilmenge der Tabellen in der Ansicht auf Spalten zu. Wenn die Tabellen mit äußeren Verknüpfungen verknüpft sind, kann (und tut) der Optimierer die nicht benötigten Tabellen aus dem Plan entfernen.
Es ist wichtig sicherzustellen, dass die Ansicht mit äußeren Verknüpfungen die richtigen Ergebnisse liefert. Wie Aaronaught gesagt hat - Sie können OUTER JOIN nicht blind durch INNER JOIN ersetzen und die gleichen Ergebnisse erwarten. Es kann jedoch vorkommen, dass dies aus Leistungsgründen bei der Verwendung von Ansichten hilfreich sein kann.
Ein letzter Hinweis: Ich habe die Auswirkungen auf die Leistung vor diesem Hintergrund nicht getestet, aber theoretisch sollten Sie in der Lage sein, einen INNER JOIN sicher durch einen OUTER JOIN zu ersetzen, wenn Sie auch die Bedingung <FOREIGN_KEY> IS NOT NULL hinzufügen zur where-Klausel.
quelle
Wenn alles so funktioniert, wie es sollte, sollte es nicht funktionieren, ABER wir alle wissen, dass nicht alles so funktioniert, wie es sollte, insbesondere wenn es um das Abfrageoptimierungsprogramm, das Zwischenspeichern von Abfrageplänen und Statistiken geht.
Zuerst würde ich vorschlagen, Index und Statistik neu zu erstellen und dann den Abfrageplan-Cache zu leeren, um sicherzustellen, dass dies nicht zu Problemen führt. Ich habe jedoch Probleme, selbst wenn das erledigt ist.
Ich habe einige Fälle erlebt, in denen eine linke Verknüpfung schneller war als eine innere Verknüpfung.
Der zugrunde liegende Grund ist folgender: Wenn Sie zwei Tabellen haben und einer Spalte mit einem Index beitreten (für beide Tabellen). Der innere Join führt zu demselben Ergebnis, unabhängig davon, ob Sie die Einträge im Index in Tabelle 1 durchlaufen und mit dem Index in Tabelle 2 übereinstimmen, als ob Sie das Gegenteil tun würden: Durchlaufen Sie die Einträge im Index in Tabelle 2 und stimmen Sie mit dem Index überein in Tabelle eins. Das Problem ist, wenn Sie irreführende Statistiken haben, verwendet das Abfrageoptimierungsprogramm die Statistiken des Index, um die Tabelle mit den am wenigsten übereinstimmenden Einträgen zu finden (basierend auf Ihren anderen Kriterien). Wenn Sie zwei Tabellen mit jeweils 1 Million haben, haben Sie in Tabelle eins 10 übereinstimmende Zeilen und in Tabelle zwei 100000 übereinstimmende Zeilen. Der beste Weg wäre, einen Index-Scan für Tabelle 1 durchzuführen und 10 Mal in Tabelle 2 abzugleichen. Die Umkehrung wäre ein Index-Scan, der über 100000 Zeilen durchläuft und versucht, 100000-mal übereinzustimmen, und nur 10 sind erfolgreich. Wenn die Statistik nicht korrekt ist, wählt der Optimierer möglicherweise die falsche Tabelle und den falschen Index für die Schleife aus.
Wenn der Optimierer die linke Verknüpfung in der Reihenfolge optimiert, in der sie geschrieben wurde, ist die Leistung besser als die der inneren Verknüpfung.
ABER der Optimierer kann auch einen linken Join suboptimal als linken Semi-Join optimieren. Um die gewünschte Auswahl zu treffen, können Sie den Force Order-Hinweis verwenden.
quelle
Probieren Sie beide Abfragen (die mit innerer und linker Verknüpfung)
OPTION (FORCE ORDER)
am Ende aus und veröffentlichen Sie die Ergebnisse.OPTION (FORCE ORDER)
ist ein Abfragehinweis, der das Optimierungsprogramm zwingt, den Ausführungsplan mit der in der Abfrage angegebenen Verknüpfungsreihenfolge zu erstellen.Wenn
INNER JOIN
die Leistung so schnell wie möglich beginntLEFT JOIN
, liegt dies daran:INNER JOIN
s besteht, spielt die Verknüpfungsreihenfolge keine Rolle. Dies gibt dem Abfrageoptimierer die Freiheit, die Verknüpfungen nach eigenem Ermessen zu ordnen, sodass das Problem möglicherweise vom Optimierer abhängt.LEFT JOIN
ist nicht der Fall, da durch Ändern der Verknüpfungsreihenfolge die Ergebnisse der Abfrage geändert werden. Dies bedeutet, dass die Engine der Join-Reihenfolge folgen muss, die Sie in der Abfrage angegeben haben. Diese ist möglicherweise besser als die optimierte.Ich weiß nicht, ob dies Ihre Frage beantwortet, aber ich war einmal in einem Projekt mit hochkomplexen Abfragen, die Berechnungen durchführten, was den Optimierer völlig durcheinander brachte. Wir hatten Fälle, in denen a
FORCE ORDER
die Ausführungszeit einer Abfrage von 5 Minuten auf 10 Sekunden verkürzte.quelle
Haben eine Reihe von Vergleichen zwischen linken äußeren und inneren Verknüpfungen durchgeführt und konnten keinen konsistenten Unterschied feststellen. Es gibt viele Variablen. Ich arbeite an einer Berichtsdatenbank mit Tausenden von Tabellen, viele mit einer großen Anzahl von Feldern, vielen Änderungen im Laufe der Zeit (Herstellerversionen und lokaler Workflow). Es ist nicht möglich, alle Kombinationen von Deckungsindizes zu erstellen, um die Anforderungen einer derart großen Vielfalt von Abfragen zu erfüllen und historische Daten zu verarbeiten. Ich habe gesehen, dass innere Abfragen die Serverleistung beeinträchtigen, weil zwei große Tabellen (Millionen bis Zehntausende von Zeilen) innerlich verbunden sind und beide eine große Anzahl von Feldern ziehen und kein Deckungsindex vorhanden ist.
Das größte Problem scheint jedoch in den obigen Diskussionen nicht aufzutreten. Möglicherweise ist Ihre Datenbank mit Triggern und einer gut gestalteten Transaktionsverarbeitung gut gestaltet, um gute Daten zu gewährleisten. Meins hat häufig NULL-Werte, bei denen sie nicht erwartet werden. Ja, die Tabellendefinitionen könnten No-Nulls erzwingen, aber das ist in meiner Umgebung keine Option.
Die Frage ist also ... Entwerfen Sie Ihre Abfrage nur auf Geschwindigkeit, eine höhere Priorität für die Transaktionsverarbeitung, bei der derselbe Code tausende Male pro Minute ausgeführt wird. Oder streben Sie nach Genauigkeit, die eine linke äußere Verbindung bietet? Denken Sie daran, dass innere Verknüpfungen auf beiden Seiten Übereinstimmungen finden müssen, sodass ein unerwarteter NULL-Wert nicht nur Daten aus den beiden Tabellen, sondern möglicherweise ganze Informationszeilen entfernt. Und es passiert so schön, keine Fehlermeldungen.
Sie können sehr schnell 90% der benötigten Daten abrufen und nicht feststellen, dass die inneren Verknüpfungen Informationen stillschweigend entfernt haben. Manchmal können innere Verknüpfungen schneller sein, aber ich glaube nicht, dass jemand diese Annahme trifft, es sei denn, er hat den Ausführungsplan überprüft. Geschwindigkeit ist wichtig, aber Genauigkeit ist wichtiger.
quelle
Ihre Leistungsprobleme sind eher auf die Anzahl der Verknüpfungen zurückzuführen, die Sie ausführen, und darauf, ob die Spalten, in denen Sie beitreten, Indizes haben oder nicht.
Im schlimmsten Fall könnten Sie leicht 9 ganze Tabellenscans für jeden Join durchführen.
quelle
Äußere Verknüpfungen bieten in Ansichten eine überlegene Leistung.
Angenommen, Sie haben eine Abfrage, die eine Ansicht umfasst, und diese Ansicht besteht aus 10 miteinander verbundenen Tabellen. Angenommen, Ihre Abfrage verwendet nur Spalten aus 3 dieser 10 Tabellen.
Wenn diese 10 Tabellen innerlich zusammengefügt worden wären, müsste das Abfrageoptimierungsprogramm sie alle zusammenfügen, obwohl Ihre Abfrage selbst nicht 7 von 10 Tabellen benötigt. Dies liegt daran, dass die inneren Verknüpfungen selbst die Daten möglicherweise herausfiltern, sodass sie für die Berechnung unerlässlich sind.
Wenn diese 10 Tabellen stattdessen äußerlich zusammengefügt worden wären, würde das Abfrageoptimierungsprogramm tatsächlich nur die erforderlichen Tabellen zusammenfügen: 3 von 10 in diesem Fall. Dies liegt daran, dass die Joins selbst die Daten nicht mehr filtern und somit nicht verwendete Joins übersprungen werden können.
Quelle: http://www.sqlservercentral.com/blogs/sql_coach/2010/07/29/poor-little-misunderstood-views/
quelle
Ich fand etwas Interessantes in SQL Server, als ich überprüfte, ob innere Verknüpfungen schneller sind als linke Verknüpfungen.
Wenn Sie die Elemente der links verknüpften Tabelle nicht in die select-Anweisung aufnehmen, ist die linke Verknüpfung schneller als dieselbe Abfrage mit innerer Verknüpfung.
Wenn Sie die links verknüpfte Tabelle in die select-Anweisung aufnehmen, war der innere Join mit derselben Abfrage gleich oder schneller als der linke Join.
quelle
Aus meinen Vergleichen geht hervor, dass sie genau den gleichen Ausführungsplan haben. Es gibt drei Szenarien:
Wenn und wann sie die gleichen Ergebnisse zurückgeben, haben sie die gleiche Geschwindigkeit. Wir müssen jedoch berücksichtigen, dass es sich nicht um dieselben Abfragen handelt und dass LEFT JOIN möglicherweise mehr Ergebnisse zurückgibt (wenn einige EIN-Bedingungen nicht erfüllt sind) - aus diesem Grund ist es normalerweise langsamer.
Wenn die Haupttabelle (die erste nicht konstante im Ausführungsplan) eine einschränkende Bedingung hat (WHERE id =?) Und die entsprechende ON-Bedingung einen NULL-Wert hat, wird die "rechte" Tabelle nicht verbunden - dies ist der Zeitpunkt LEFT JOIN ist schneller.
Wie in Punkt 1 erläutert, ist INNER JOIN normalerweise restriktiver und liefert weniger Ergebnisse und ist daher schneller.
Beide verwenden (dieselben) Indizes.
quelle