Umgebung: SQL 2008 R2
Ich habe eine abgeleitete Tabelle mit einer Unterabfrage erstellt und mit der Haupttabelle verknüpft. Ich möchte nur wissen, ob die Unterabfrage nur einmal ausgeführt wird oder für jede Zeile in der Ergebnismenge ausgeführt wird. Betrachten Sie folgendes Beispiel (fiktive Tabellennamen nur als Referenz)
%Vor%Also wird die für Inner Join verwendete Unterabfrage nur einmal oder mehrmals ausgeführt?
Wenn ich obige Abfrage mit OUTER APPLY neu schreibe, weiß ich sicher, dass die Unterabfrage für jede Zeile ausgeführt wird. Siehe unten.
%Vor%Ich möchte nur sicherstellen, dass Innerer Join die Unterabfrage nur einmal ausführt.
Zunächst ist zu beachten, dass Ihre Abfragen nicht vergleichbar sind, OUTER APPLY
muss durch CROSS APPLY
oder INNER JOIN
durch LEFT JOIN
ersetzt werden.
Wenn sie jedoch vergleichbar gemacht werden, können Sie sehen, dass die Abfragepläne für beide Abfragen identisch sind. Ich habe gerade ein Beispiel DDL verspottet:
%Vor%Ausführen des folgenden:
%Vor%Gibt den folgenden Plan:
Und zu INNER / CROSS wechseln:
%Vor%Gibt den folgenden Plan:
Dies sind die Pläne, bei denen keine Daten in den äußeren Tabellen und nur eine Zeile in den Mitarbeitern vorhanden sind, also nicht wirklich realistisch. Im Falle der äußeren Anwendung kann SQL Server feststellen, dass es nur eine Zeile in den Mitarbeitern gibt. Daher wäre es vorteilhaft, nur eine Nested-Loop-Verknüpfung (d. H. Zeilenweise Suche) mit den äußeren Tabellen durchzuführen. Nach dem Einfügen von 1.000 Zeilen in Mitarbeiter ergibt die Verwendung von LEFT JOIN / OUTER APPLY den folgenden Plan:
Sie können hier sehen, dass der Join nun ein Hash-Match-Join ist, was bedeutet, dass SQL Server festgestellt hat, dass es am besten ist, die äußere Abfrage zuerst auszuführen, die Ergebnisse zu hashen und dann von Mitarbeitern zu suchen . Dies bedeutet jedoch nicht, dass die Unterabfrage als Ganzes ausgeführt und die Ergebnisse gespeichert werden. Zur Vereinfachung könnten Sie dies berücksichtigen, aber Prädikate aus der äußeren Abfrage können immer noch verwendet werden, z. B. wenn die Unterabfrage intern ausgeführt und gespeichert wurde , würde die folgende Abfrage massiven Aufwand darstellen:
%Vor% Was wäre der Sinn, alle Mitarbeiter-Tarife abzurufen, die Ergebnisse zu speichern, nur um einen Mitarbeiter nachzuschlagen? Die Überprüfung des Ausführungsplans zeigt, dass das Prädikat EID = 1
an den Tabellenscan in #AttendanceDetails
übergeben wird:
Die Antwort auf die folgenden Punkte lautet also:
Es kommt darauf an . Die Verwendung von APPLY
SQL Server wird versuchen, die Abfrage möglichst als JOIN neu zu schreiben, da dies den optimalen Plan ergibt, sodass die Verwendung von OUTER APPLY
nicht garantiert, dass die Abfrage für jede Zeile einmal ausgeführt wird. In ähnlicher Weise garantiert die Verwendung von LEFT JOIN
nicht, dass die Abfrage nur einmal ausgeführt wird.
SQL ist eine deklarative Sprache, in der Sie angeben, was Sie tun möchten und nicht wie Sie es tun sollen. Sie sollten sich also nicht auf bestimmte Befehle verlassen, um ein bestimmtes Verhalten auszulösen. Wenn Sie Leistungsprobleme feststellen, überprüfen Sie dies den Ausführungsplan und IO-Statistiken, um herauszufinden, wie es funktioniert, und um herauszufinden, wie Sie Ihre Abfrage verbessern können.
Darüber hinaus matalisiert SQL Server keine Unterabfragen, normalerweise wird die Definition in die Hauptabfrage erweitert, also obwohl Sie Folgendes geschrieben haben:
%Vor%Was tatsächlich ausgeführt wird, ist eher wie folgt:
%Vor%Mit INNER JOIN wird Ihre Sub-Query nur einmal ausgeführt und ihre Datensätze werden intern in tempdb worktable für komplexe Operationen gespeichert und dann mit der ersten Tabelle verbunden.
Mit der APPLY-Klausel wird die Unterabfrage für jede Zeile in der ersten Tabelle ausgeführt.
edit: Verwenden Sie CTE
%Vor%Tags und Links sql-server sql-server-2008 join subquery