Jef*_*nCO 11 join sql-server syntax sql-server-2012
TLDR;如果您查看 2 个执行计划,是否可以轻松回答哪个更好?我故意没有创建索引,所以更容易看到发生了什么。
继续我之前的问题,我们发现不同连接样式(即嵌套与传统)之间的查询性能差异,我意识到嵌套语法也会修改查询的行为。考虑以下 2 个查询。
SELECT a.*, m.*, n.*
FROM dbo.Autos a
LEFT JOIN dbo.Models m
JOIN dbo.Manufacturers n -- <-- Nested INNER JOIN
ON n.ManufacturerID = m.ManufacturerID
ON m.ModelID = a.ModelID
Run Code Online (Sandbox Code Playgroud)

这并不一定使制造商加入,以包括与ModelID自动行是不是在型号表。

使用传统语法,我们必须将 Manufactures 的连接更改为外部连接,就像这样……但这会改变查询计划。
SELECT a.*, m.*, n.*
FROM dbo.Autos a
LEFT JOIN dbo.Models m
ON m.ModelID = a.ModelID
LEFT JOIN dbo.Manufacturers n -- <-- Now LEFT OUTER JOIN
ON n.ManufacturerID = m.ManufacturerID
Run Code Online (Sandbox Code Playgroud)

Pau*_*ite 13
如果您查看 2 个执行计划,是否可以轻松回答哪个更好?我故意没有创建索引,所以更容易看到发生了什么。
第二个计划的估计成本较低,因此在有限的意义上它“更好”。
数据集非常小,优化器没有花太多时间寻找替代方案。查询的第一种形式恰好在早期使用散列连接和表假脱机找到计划。该计划的估计成本如此之低,以至于优化器不会费心寻找更好的东西。
查询的第二种形式恰好在搜索过程的早期仅使用嵌套循环外连接找到一个计划,并且优化器再次决定该计划足够好。碰巧这个计划估计更便宜。
也就是说(如问题评论中所述)这两个查询在语义上并不相同。如果您可以保证数据库未来所有可能状态的结果始终相同,那么这对您来说可能并不重要,但优化器无法做出这种假设。它只生成保证在所有情况下生成 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;
Run Code Online (Sandbox Code Playgroud)
这个形式清楚地表明,逻辑要求是左连接 fromAutos到内连接到的结果。省略可选括号给出了你称之为“嵌套”的形式:ManufacturersModels
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;
Run Code Online (Sandbox Code Playgroud)
这不是一种不同的语法——它只是省略了可选的括号并重新格式化了一下。
正如 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;
Run Code Online (Sandbox Code Playgroud)
以上三种查询形式都使用相同的 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;
Run Code Online (Sandbox Code Playgroud)
使用传统语法,我们必须将连接更改为`Manufacturers 到外部连接,就像这样......但这会改变查询计划。
这可能会改变查询的含义,在这种情况下,它在技术上不是有效的替代方案(但请参阅ypercube对您的问题的 评论)。
ANSI 连接语法中的(可选)括号正好用于更复杂的连接要求,因此您不应该害怕在必要时使用它们。
| 归档时间: |
|
| 查看次数: |
41128 次 |
| 最近记录: |