Questa non è assolutamente una risposta canonica, ma ho notato che per i piani di query dei loop nidificati mostrati nel violino SQL è stato possibile applicare il piano da Query 2 a Query 1 con l'uso del USE PLAN
suggerimento, ma il tentativo di eseguire l'operazione inversa non riesce con
Il processore di query non è stato in grado di produrre un piano di query poiché il suggerimento USE PLAN contiene un piano che non è stato verificato essere legale per la query. Rimuovere o sostituire il suggerimento USE PLAN. Per una migliore probabilità di forzatura del piano riuscita, verificare che il piano fornito nel suggerimento USE PLAN sia generato automaticamente da SQL Server per la stessa query.
La disabilitazione della regola di trasformazione dell'ottimizzatore ReorderLOJN
impedisce anche il suggerimento del piano precedentemente eseguito correttamente.
Sperimentare una maggiore quantità di dati mostra che SQL Server è sicuramente in grado di trasformarsi (A LOJ B) LOJ C
in modo A LOJ (B LOJ C)
naturale, ma non ho visto alcuna prova che sia vero il contrario.
È un caso molto forzato in cui la prima query ha prestazioni migliori della seconda
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]
Che dà piani
Per me la Query 1 ha avuto un tempo trascorso di 108 ms contro 1.163 ms per la Query 2.
Query 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
Query 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
Quindi si potrebbe presumere provvisoriamente che la prima sintassi ("non verificata") sia potenzialmente vantaggiosa in quanto consente di prendere in considerazione un numero maggiore di potenziali ordini di join, ma non ho svolto test sufficientemente esaustivi per avere molta fiducia in questo come regola generale.
Potrebbe essere del tutto possibile trovare esempi contrari in cui Query 2 ha prestazioni migliori. Prova entrambi e guarda i piani di esecuzione.