Это абсолютно не канонический ответ, но я заметил, что для планов запросов с вложенными циклами, показанных в скрипте SQL, можно было применить план из Query 2 к Query 1 с использованием USE PLANподсказки, но попытка выполнить обратную операцию не удалась с помощью
Обработчику запросов не удалось создать план запроса, поскольку подсказка USE PLAN содержит план, который не может быть проверен как законный для запроса. Удалите или замените подсказку USE PLAN. Чтобы повысить вероятность успешного форсирования плана, убедитесь, что план, предоставленный в подсказке USE PLAN, автоматически генерируется SQL Server для того же запроса.
Отключение правила преобразования оптимизатора также ReorderLOJN предотвращает успешное выполнение ранее выполненной подсказки плана.
Эксперименты с большим количеством данных показывают, что SQL Server, безусловно, способен преобразовываться (A LOJ B) LOJ Cв A LOJ (B LOJ C)естественные условия, но я не видел никаких доказательств того, что обратное верно.
Очень надуманный случай, когда первый запрос работает лучше, чем второй
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]
Который дает планы

Для меня Query 1 имел истекшее время 108 мс против 1163 мс для Query 2.
Запрос 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
Запрос 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
Таким образом, можно условно предположить, что первый («неопубликованный») синтаксис потенциально полезен, поскольку позволяет учитывать больше потенциальных порядков соединения, но я не провел достаточно исчерпывающего тестирования, чтобы иметь большую уверенность в этом как общем правиле.
Вполне возможно, можно придумать встречные примеры, где Query 2 работает лучше. Попробуйте оба и посмотрите на планы выполнения.