Sql server 将约束移动到连接中是否比连接和where子句更有效?

Sql server 将约束移动到连接中是否比连接和where子句更有效?,sql-server,sql-server-2008,tsql,Sql Server,Sql Server 2008,Tsql,我一直在尝试测试这一点,但我对我的测试有怀疑,因为时间安排差异太大 -- Scenario 1 SELECT * FROM Foo f INNER JOIN Bar b ON f.id = b.id WHERE b.flag = true; -- Scenario 2 SELECT * FROM Foo f INNER JOIN Bar b ON b.flag = true AND f.id = b.id; 从逻辑上看,场景2的效率似乎更高,但我不确定SQL

我一直在尝试测试这一点,但我对我的测试有怀疑,因为时间安排差异太大

-- Scenario 1
SELECT * FROM Foo f 
    INNER JOIN Bar b ON f.id = b.id 
    WHERE b.flag = true;

-- Scenario 2 
SELECT * FROM Foo f 
    INNER JOIN Bar b ON b.flag = true AND f.id = b.id;

从逻辑上看,场景2的效率似乎更高,但我不确定SQL server是否足够聪明来优化它。

不确定为什么您认为场景2“从逻辑上”更高效。在
内部连接上
基本上所有内容都是一个过滤器,因此SQL Server可以将逻辑折叠为完全相同的底层计划形状。以下是AdventureWorks2012()中的一个示例:

我更喜欢将连接条件与筛选条件分开,因此将始终以左侧的格式编写查询。然而@HLGEM提出了一个很好的观点,这些子句在这种情况下是可互换的,因为它是一个
内部连接。对于
外部联接
,将筛选器放在联接条件中的外部表上是非常重要的,否则您会无意中得到
内部联接
,并彻底更改查询的语义。因此,我关于如何折叠计划的建议仅适用于内部联接

如果您担心性能,我会先去掉
SELECT*
,只拉取您实际需要的列(并确保有一个覆盖索引)


四个月后,另一个答案出现了,声称性能通常会有所不同,在
ON
子句中加入过滤标准会更好。虽然我不会质疑这种情况确实可能发生,但我认为这肯定不是标准,也不应该成为您总是将所有筛选条件放在
ON
子句中的借口。

接受的答案仅适用于您的测试用例

如前所述,标题问题的答案是是,将约束移动到连接条件可以极大地改进查询并确保。我见过类似的形式(但可能不完全如此)


…没有优化到与“on join”等价物相同的计划,因此我倾向于将“on join”约束用作最佳实践,即使对于可能以最佳方式解决的简单情况也是如此。

执行计划应该是相同的。因为不知道SQL如何解释查询,似乎在加入之前过滤要加入的集合比加入所有内容然后过滤效率更高。Marcin是对的他们有相同的执行计划。我不熟悉使用执行计划-它们做得很好。标题可能应该改为明确地说“内部联接”,因为对于外部联接,执行计划通常会有所不同。我要补充一点,如果使用左联接,在将条件放入join或where子句中时,重新启动集将有所不同。所以它在这方面有区别,但在性能上不如在结果上有区别。@HLGEM是的,这是真的。对于交叉连接也是如此。:-)我只处理内心,因为这是问题中特别提到的。干杯。我知道你知道这一点,但似乎很少有开发人员意识到这一点,我只是想我应该提及这一点,以便其他阅读此问题的人不会对他们的问题做出错误的假设。与其向我们保证这会发生,您可以为实际查询提供优化器生成的2个表单和2个不同的计划。否则,您对最佳实践的建议会与其他人的意见相冲突,其中包括SQL Server社区中知名的Aaron Bertrand和Paul White等人。尽管某些场景可能会根据子句的位置演示不同的优化路径!我怀疑这是非常罕见的!我会逻辑地编写查询(join-criteria=ON,filter-criteria=WHERE),除非我有一个性能理由来研究替代方案。你说的好像我上面的演示是个例外,但是你能想到的最好的证据是“它是这样的东西”?如果你想让人们听你的主张,请展示一个真实的例子,说明你所说的是正确的。否则就是蛇油。是的,我应该可以发布一些东西来支持这个说法。
select * 
  from A
 inner join B
    on B.id = a.id
 inner join C
    on C.id = A.id
 where B.z = 1 and C.z = 2;