Dies ist absolut keine kanonische Antwort, aber ich habe festgestellt, dass es für die in der SQL-Geige gezeigten Abfragepläne für verschachtelte Schleifen möglich war, den Plan unter Verwendung des USE PLAN
Hinweises von Abfrage 2 auf Abfrage 1 anzuwenden, aber der Versuch der umgekehrten Operation schlägt fehl
Der Abfrageprozessor konnte keinen Abfrageplan erstellen, da der Hinweis "USE PLAN" einen Plan enthält, der nicht als für die Abfrage zulässig überprüft werden konnte. Entfernen oder ersetzen Sie den USE PLAN-Hinweis. Stellen Sie sicher, dass der im USE PLAN-Hinweis angegebene Plan von SQL Server automatisch für dieselbe Abfrage generiert wird, um die Wahrscheinlichkeit eines erfolgreichen Planerzwingens zu erhöhen.
Durch Deaktivieren der Optimierungsumwandlungsregel wird ReorderLOJN
verhindert, dass der zuvor erfolgreiche Planhinweis ebenfalls erfolgreich ist.
Das Experimentieren mit größeren Datenmengen zeigt, dass SQL Server sicherlich auch (A LOJ B) LOJ C
auf A LOJ (B LOJ C)
natürliche Weise transformiert werden kann , aber ich habe keine Beweise dafür gesehen, dass das Gegenteil der Fall ist.
Ein sehr ausgeklügelter Fall, in dem die erste Abfrage eine bessere Leistung erbringt als die zweite
DROP TABLE MyGrandChild , MyChild, MyParent
CREATE TABLE MyParent
(Id int)
CREATE TABLE MyChild
(Id int PRIMARY KEY
,ParentId int,
Filler char(8000) NULL)
CREATE TABLE MyGrandChild
(Id int
,ParentId int)
INSERT INTO MyChild
(Id, ParentId)
SELECT TOP (100000) ROW_NUMBER() OVER (ORDER BY @@SPID),
ROW_NUMBER() OVER (ORDER BY @@SPID)
FROM master..spt_values v1, master..spt_values
INSERT INTO MyGrandChild
(Id, ParentId)
OUTPUT INSERTED.Id INTO MyParent
SELECT TOP (3000) Id, Id AS ParentId
FROM MyChild
ORDER BY Id
SET STATISTICS IO ON;
SET STATISTICS TIME ON;
SELECT gc.Id AS gcId,
gc.ParentId AS gcpId,
c.Id AS cId,
c.ParentId AS cpId,
p.Id AS pId
FROM MyGrandChild AS gc
LEFT OUTER JOIN MyChild AS c
ON c.[Id] = gc.[ParentId]
LEFT OUTER JOIN MyParent AS p
ON p.[Id] = c.[ParentId]
SELECT gc.Id AS gcId,
gc.ParentId AS gcpId,
c.Id AS cId,
c.ParentId AS cpId,
p.Id AS pId
FROM MyGrandChild AS gc
LEFT OUTER JOIN( MyChild AS c
LEFT OUTER JOIN MyParent AS p
ON p.[Id] = c.[ParentId])
ON c.[Id] = gc.[ParentId]
Welches gibt Pläne
Für mich hatte Abfrage 1 eine verstrichene Zeit von 108 ms gegenüber 1.163 ms für Abfrage 2.
Abfrage 1
Table 'Worktable'. Scan count 0, logical reads 0
Table 'MyChild'. Scan count 0, logical reads 9196
Table 'MyGrandChild'. Scan count 1, logical reads 7
Table 'MyParent'. Scan count 1, logical reads 5
Abfrage 2
Table 'MyParent'. Scan count 1, logical reads 15000
Table 'MyChild'. Scan count 0, logical reads 9000
Table 'MyGrandChild'. Scan count 1, logical reads 7
Es kann daher vorläufig davon ausgegangen werden, dass die erste ("nicht verschachtelte") Syntax potenziell vorteilhaft ist, da dadurch mehr potenzielle Verknüpfungsaufträge berücksichtigt werden können, aber ich habe nicht ausführlich genug getestet, um in der Regel viel Vertrauen in diese zu haben.
Es ist durchaus möglich, Gegenbeispiele zu erstellen, bei denen Abfrage 2 eine bessere Leistung erbringt. Probieren Sie beide aus und sehen Sie sich die Ausführungspläne an.