谓词:在 WHERE 子句还是 JOIN 子句中?

Han*_*non 16 sql-server optimization

查看Kalen Delaney 撰写的“SQL Server 2008 Internals” 1,第 13 页,它说明了以下内容:

“生成这样一个计划的第一步是规范化每个查询,这可能会将单个查询分解为多个细粒度的查询。查询优化器在规范化一个查询之后对其进行优化,这意味着它确定了一个计划执行该查询。”

另一位 DBA 向我建议,可以通过将WHERE子句谓词移动到FROM子句中来提高某些查询的性能,例如:

SELECT *
FROM dbo.table1 t1
    INNER JOIN dbo.table3 t3 ON t1.ID = t3.ID
    LEFT OUTER JOIN dbo.table2 t2 ON t1.ID = t2.ID
WHERE t1.CreateDate >= '2015-07-31 00:00:00';
Run Code Online (Sandbox Code Playgroud)

会成为:

SELECT *
FROM dbo.table1 t1
    INNER JOIN dbo.table3 t3 ON t1.ID = t3.ID
        AND t1.CreateDate >= '2015-07-31 00:00:00'
    LEFT OUTER JOIN dbo.table2 t2 ON t1.ID = t2.ID;
Run Code Online (Sandbox Code Playgroud)

显然,第一个示例的含义是查询优化器将执行第JOIN一个,然后应用该WHERE子句,对于具有大表的复杂查询,这将不如我们手动将查询重新编写为第二个示例中显示的形式. 显然这仅适用于连接,即如果这是一个连接,则规范化器实际上会将WHERE谓词移动到FROM子句中。

有人可以确认这种行为吗?是否有一些文档可以查看?我可以在执行计划中看到这个吗?


1 - 是的,我知道这是古老的。

小智 3

我想这是“视情况而定”的时刻之一。在常规执行中,没有或至少几乎没有差异。

我认为一旦查询变得更加复杂,它就会变得更有趣。更复杂的场景例如:

  • 嵌套连接
  • 强制订单(查询提示)

我也会添加 LEFT 和 CROSS Joins,认为它们已经是您示例的一部分。

关于“SQL Server规范化的经验”——我想说,除了看代码之外,你没有什么可以坚持的。通常只是一句“看情况!”