Warum spielt die Reihenfolge der join-Klauseln betreffen den Abfrageplan in SQL Server?
Baue ich eine Ansicht in SQL Server 2000 (und 2005) und ich habe bemerkt, dass die Reihenfolge der join-Anweisungen beeinflusst die Ausführung planen und die Geschwindigkeit der Abfrage.
select sr.WTSASessionRangeID,
-- bunch of other columns
from WTSAVW_UserSessionRange us
inner join WTSA_SessionRange sr on sr.WTSASessionRangeID = us.WTSASessionRangeID
left outer join WTSA_SessionRangeTutor srt on srt.WTSASessionRangeID = sr.WTSASessionRangeID
left outer join WTSA_SessionRangeClass src on src.WTSASessionRangeID = sr.WTSASessionRangeID
left outer join WTSA_SessionRangeStream srs on srs.WTSASessionRangeID = sr.WTSASessionRangeID
--left outer join MO_Stream ms on ms.MOStreamID = srs.MOStreamID
left outer join WTSA_SessionRangeEnrolmentPeriod srep on srep.WTSASessionRangeID = sr.WTSASessionRangeID
left outer join WTSA_SessionRangeStudent stsd on stsd.WTSASessionRangeID = sr.WTSASessionRangeID
left outer join WTSA_SessionSubrange ssr on ssr.WTSASessionRangeID = sr.WTSASessionRangeID
left outer join WTSA_SessionSubrangeRoom ssrr on ssrr.WTSASessionSubrangeID = ssr.WTSASessionSubrangeID
left outer join MO_Stream ms on ms.MOStreamID = srs.MOStreamID
Auf SQL Server 2000, die obige Abfrage generiert kontinuierlich einen plan, der Kosten-946. Wenn ich die Auskommentierung der MO_Stream sich in der Mitte der Abfrage und kommentieren Sie die ein an der Unterseite, die Kosten Tropfen auf 263. Die Ausführungsgeschwindigkeit sinkt entsprechend. Ich dachte immer, dass der query optimizer würde die Abfrage interpretieren entsprechend ohne Berücksichtigung der join-Reihenfolge, aber es scheint, die Reihenfolge ist wichtig.
Also da, um hat scheint es, gibt es eine join-Strategie sollte ich für das schreiben schneller Abfragen?
(Übrigens auf SQL Server 2005 mit fast identischen Daten, der Abfrage-plan wurden die Kosten 0.675 und 0.631 werden.)
Edit: Auf SQL Server 2000, hier sind die profilierten stats:
946-cost query: 9094ms CPU, 5121 reads, 0 writes, 10123ms duration
263-cost query: 172ms CPU, 7477 reads, 0 writes, 170ms duration
Edit: Hier wird die logische Struktur der Tabellen.
SessionRange ---+--- SessionRangeTutor
|--- SessionRangeClass
|--- SessionRangeStream --- MO_Stream
|--- SessionRangeEnrolmentPeriod
|--- SessionRangeStudent
+----SessionSubrange --- SessionSubrangeRoom
Edit: vielen Dank an Alex und gbn für den Hinweis mich in die richtige Richtung. Ich fand auch diese Frage.
Hier ist das neue-Abfrage:
select sr.WTSASessionRangeID // + lots of columns
from WTSAVW_UserSessionRange us
inner join WTSA_SessionRange sr on sr.WTSASessionRangeID = us.WTSASessionRangeID
left outer join WTSA_SessionRangeTutor srt on srt.WTSASessionRangeID = sr.WTSASessionRangeID
left outer join WTSA_SessionRangeClass src on src.WTSASessionRangeID = sr.WTSASessionRangeID
left outer join WTSA_SessionRangeEnrolmentPeriod srep on srep.WTSASessionRangeID = sr.WTSASessionRangeID
left outer join WTSA_SessionRangeStudent stsd on stsd.WTSASessionRangeID = sr.WTSASessionRangeID
// SessionRangeStream is a many-to-many mapping table between SessionRange and MO_Stream
left outer join (
WTSA_SessionRangeStream srs
inner join MO_Stream ms on ms.MOStreamID = srs.MOStreamID
) on srs.WTSASessionRangeID = sr.WTSASessionRangeID
// SessionRanges MAY have Subranges and Subranges MAY have Rooms
left outer join (
WTSA_SessionSubrange ssr
left outer join WTSA_SessionSubrangeRoom ssrr on ssrr.WTSASessionSubrangeID = ssr.WTSASessionSubrangeID
) on ssr.WTSASessionRangeID = sr.WTSASessionRangeID
SQLServer2000 Kosten: 24.9
Du musst angemeldet sein, um einen Kommentar abzugeben.
Da muss ich widersprechen, mit allen bisherigen Antworten, und der Grund ist einfach: wenn Sie ändern die Reihenfolge der left join, Ihre Abfragen sind logischerweise unterschiedlich und sind als solche, die Sie produzieren unterschiedliche Ergebnismengen. Sehen Sie selbst:
Die join-Reihenfolge macht einen Unterschied für die resultierende Abfrage. Dies ist dokumentiert in BOL in den docs für AUS:
Können Sie ändern Sie die join-Reihenfolge mit Klammern um die joins (BOL zeigt sich dies in der syntax an der Spitze des docs, aber es ist leicht zu übersehen).
Dies ist bekannt als chiastic Verhalten. Sie können auch verwenden Sie den Abfrage-Hinweis
OPTION (FORCE ORDER)
zu zwingen, eine spezielle join-Reihenfolge, aber dies kann dazu führen, die sogenannten "bushy-Pläne", die kann nicht die optimale für die Abfrage ausgeführt wird.Offensichtlich, die SQL Server 2005-Abfrageoptimierer ist viel besser als der SQL-Server 2000 ein.
Jedoch, es gibt eine Menge Wahrheit in deiner Frage. Outer-joins wird die Ausführung sehr stark variieren basierend auf der Reihenfolge (inner joins neigen, optimiert werden, um die effizienteste route, aber auch wieder um Angelegenheiten). Wenn Sie darüber nachdenken, wie Sie bauen oben Links schließt sich, die Sie brauchen, um herauszufinden, was zum Teufel ist auf der linken Seite. Als solche, jede join berechnet werden muss, bevor alle anderen beitreten getan werden kann. Es wird sequenziell und nicht parallel. Nun, offensichtlich gibt es Dinge, die Sie tun können, um diese zu bekämpfen (wie Indizes, Ansichten, etc). Aber, der Punkt steht: Die Tabelle muss wissen, was auf der linken Seite, bevor Sie es tun können einen left outer join. Und wenn Sie gerade halten Sie das hinzufügen schließt sich, Sie werden immer mehr und mehr der Abstraktion zu, was genau ist auf der linken Seite (vor allem wenn Sie mit verknüpften Tabellen, wie die linke Tabelle!).
Mit inner joins, allerdings können Sie parallelisieren, diejenigen, die ganz ein bisschen, es gibt also weniger einen dramatischen Unterschied, wie weit, um ' s betrifft.
Einer Allgemeinen Strategie für die Optimierung von Abfragen mit JOINs zu betrachten, das Datenmodell und die Daten und versuchen zu bestimmen, welche JOINs reduzieren die Anzahl der Datensätze, die berücksichtigt werden müssen, die die meisten schnell. Die weniger Datensätze, die berücksichtigt werden müssen, desto schneller wird die Abfrage ausgeführt wird. Der server wird in der Regel produzieren einen besseren Abfrageplan zu.
Zusammen mit den oben genannten Optimierung stellen Sie sicher, dass alle Felder verwendet, die in JOINs indiziert
Abfrage ist wahrscheinlich sowieso falsch. Alex ist richtig. Eric mag richtig sein, auch, aber die Abfrage ist falsch.
Lets' nehmen diese Teilmenge:
Beitreten WTSA_SessionSubrangeRoom auf WTSA_SessionSubrange. Sie dürfen keine Zeilen aus WTSA_SessionSubrange.
Die Verknüpfung sollte so sein:
Dies ist der Grund, warum der join-Reihenfolge ist, die Ergebnisse, weil es ein anderen Abfrage, deklarativ zu sprechen.
Hättest du auch ändern müssen, der
MO_Stream
undWTSA_SessionRangeStream
auch mitzumachen.es hängt davon ab, welche die verknüpften Felder indiziert sind - wenn Sie zum Scannen der Tabelle ist das erste Feld, sondern ein index auf die zweite, es ist langsam. Wenn Sie Ihre erste join-Feld ist ein index, es werde schneller sein. Meine Vermutung ist, dass 2005 optimiert es besser durch die Bestimmung der indizierten Felder und der Durchführung dieser ersten
In DevConnections vor ein paar Jahren eine Sitzung auf die Leistung von SQL Server erklärt, dass (a) die Reihenfolge der outer-joins NICHT egal ist, und (b) wenn eine Abfrage eine Menge von Verknüpfungen, es wird nicht Blick auf alle von Ihnen, bevor Sie eine Entscheidung über einen plan. Wenn Sie wissen, Sie haben joins, die helfen, beschleunigen eine Abfrage, sollten Sie frühzeitig in der Liste (wenn Sie können).