Isso absolutamente não é uma resposta canônica, mas notei que, para os planos de consulta de loops aninhados mostrados no SQL Fiddle, era possível aplicar o plano da Consulta 2 à Consulta 1 com o uso da USE PLAN
dica, mas a tentativa de operação inversa falha com
O processador de consultas não pôde produzir o plano de consulta porque a dica USE PLAN contém um plano que não pode ser verificado como legal para a consulta. Remova ou substitua a dica USE PLAN. Para melhor probabilidade de forçar o plano com êxito, verifique se o plano fornecido na dica USE PLAN é um gerado automaticamente pelo SQL Server para a mesma consulta.
Desabilitar a regra de transformação do otimizador ReorderLOJN
impede que a dica de plano previamente bem-sucedida também seja bem-sucedida.
Experiências com maiores quantidades de dados mostra que o SQL Server é certamente capaz de transformar (A LOJ B) LOJ C
a A LOJ (B LOJ C)
naturalmente bem, mas eu não vi qualquer evidência de que o inverso é verdadeiro.
Um caso muito artificial em que a primeira consulta tem um desempenho melhor que a segunda é
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]
O que dá planos
Para mim, a consulta 1 teve um tempo decorrido de 108 ms vs 1.163 ms para a consulta 2.
Consulta 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
Consulta 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
Portanto, pode-se presumir provisoriamente que a primeira sintaxe ("não aninhada") é potencialmente benéfica, pois permite que mais pedidos de associação em potencial sejam considerados, mas eu não fiz testes exaustivos o suficiente para ter muita confiança nisso como regra geral.
Pode ser perfeitamente possível criar exemplos de contador em que a Consulta 2 tenha um desempenho melhor. Experimente os dois e veja os planos de execução.