如果您查看这两个执行计划,有一个简单的答案是哪个更好?我故意没有创建索引,因此更容易看到正在发生的事情。
第二个计划的估计成本较低,因此从有限的角度来看,它是“更好的”计划。
数据集是如此之小,以至于优化器没有花太多时间在寻找替代方案上。查询的第一种形式恰好是在早期使用哈希联接和表假脱机找到计划的。该计划的估计成本如此之低,以至于优化器不会费心寻找任何更好的东西。
查询的第二种形式恰好是在搜索过程的早期阶段仅使用嵌套循环外部联接来查找计划,然后优化程序再次确定该计划足够好。碰巧这种计划估计会更便宜。
也就是说(如问题注释中所述),这两个查询在语义上并不相同。如果可以保证对于数据库的所有将来状态,结果始终是相同的,那么这对您可能并不重要,但是优化器无法做出此假设。在所有情况下,它只会生成保证产生SQL指定的相同结果的计划。
我已经意识到,嵌套语法还可以修改查询的行为。
“嵌套语法”只是整个ANSI连接语法规范的一方面。为了对更复杂的连接模式启用完整的逻辑规范,该规范允许(可选)括号和FROM
子句子查询。
可以使用括号使用相同的ANSI语法编写查询:
SELECT
A.*,
M.*,
N.*
FROM dbo.Autos AS A
LEFT JOIN
(
dbo.Manufacturers AS N
JOIN dbo.Models AS M
ON M.ManufacturerID = N.ManufacturerID
) ON M.ModelID = A.ModelID;
这种形式清楚地表明,该逻辑的要求是从左连接Autos
到结果内接合Manufacturers
到Models
。省略可选的括号将使您称之为“嵌套”形式:
SELECT
A.*,
M.*,
N.*
FROM dbo.Autos AS A
LEFT JOIN dbo.Manufacturers AS N
JOIN dbo.Models AS M
ON M.ManufacturerID = N.ManufacturerID
ON M.ModelID = A.ModelID;
这不是不同的语法-只是省略了可选的括号并重新格式化了一点。
正如Martin所提到的,在这种情况下,也可以使用内部联接,然后是右外部联接来表达逻辑要求:
SELECT
A.*,
M.*,
N.*
FROM dbo.Manufacturers AS N
JOIN dbo.Models AS M
ON M.ManufacturerID = N.ManufacturerID
RIGHT JOIN dbo.Autos AS A
ON A.ModelID = M.ModelID;
以上所有三种查询形式都使用相同的ANSI连接语法。这三者也碰巧使用提供的数据集产生了相同的物理执行计划:
正如我在对上一个问题的回答中提到的那样,表达完全相同的逻辑要求的查询不一定会产生相同的执行计划。您更喜欢使用哪种逻辑查询形式,很大程度上取决于样式。通常,一种特定样式与“更好”的查询计划之间没有关联。如果新查询在逻辑上与原始查询并不完全相同,通常建议不要重写查询以获取特定计划。
SQL标准还允许FROM
子句子查询,因此编写相同查询规范的另一种方法是:
SELECT *
FROM dbo.Autos AS A
LEFT JOIN
(
SELECT
N.ManufacturerID,
ManufacturerName = N.Name,
M.ModelID,
ModelName = M.Name
FROM dbo.Manufacturers AS N
JOIN dbo.Models AS M
ON M.ManufacturerID = N.ManufacturerID
) AS R1
ON R1.ModelID = A.ModelID;
使用传统语法,我们必须将`制造商的联接更改为外部联接,就像这样...,但这会更改查询计划。
这可能会更改查询的含义,在这种情况下,从技术上讲,这不是有效的选择(但请参见ypercube对您的问题的 评论)。
ANSI连接语法中的(可选)括号正是针对更复杂的连接要求,因此,您不必担心在必要时使用它们。