9

我一直在尝试对此进行测试,但由于时间差异很大,我对我的测试表示怀疑。

-- 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 服务器是否足够聪明来优化它。

4

2 回答 2

14

不知道为什么你认为场景 2 会“逻辑上”是more efficient. 一切基本上都是一个INNER JOIN过滤器,因此 SQL Server 可以将逻辑折叠到完全相同的底层计划形状。这是 AdventureWorks2012 的一个示例(点击放大):

在此处输入图像描述

我更喜欢将连接条件与过滤条件分开,因此将始终以左侧的格式编写查询。但是@HLGEM 提出了一个很好的观点,这些子句在这种情况下是可以互换的,只是因为它是一个INNER JOIN. 对于 an OUTER JOIN,将过滤器放在连接条件中的外部表上非常重要,否则您会不知不觉地以 an 结束INNER JOIN并彻底改变查询的语义。所以我关于如何折叠计划的建议只适用于内部连接。

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

四个月后,出现了另一个答案,声称通常会有性能差异,并且将过滤条件放在ON子句中会更好。虽然我不会质疑这肯定是有可能发生的,但我认为这肯定不是常态,也不应该成为你总是将所有过滤条件都放在ON子句中的借口。

于 2013-04-02T21:45:26.900 回答
-5

接受的答案仅对您的测试用例是正确的。

如前所述,对标题问题的回答是肯定的,将约束移动到连接条件可以大大改善查询和确保。我见过类似的形式(但可能不完全)......

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;

...没有优化到与“加入时”等效项相同的计划,因此我倾向于使用“加入时”约束作为最佳实践,即使对于可能以任何方式得到最佳解决的更简单的情况也是如此。

于 2013-08-03T09:24:23.297 回答