tug*_*erk 41 sql t-sql sql-server inner-join sql-server-2008-r2
假设我有以下T-SQL代码:
SELECT * FROM Foo f
INNER JOIN Bar b ON b.BarId = f.BarId;
WHERE b.IsApproved = 1;
Run Code Online (Sandbox Code Playgroud)
以下一行也返回相同的行集:
SELECT * FROM Foo f
INNER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId);
Run Code Online (Sandbox Code Playgroud)
这可能不是这里最好的案例样本,但这两者之间是否有任何性能差异?
Stu*_*tLC 43
请注意与外连接的区别.将b.IsApproved(在右表,Bar上)的过滤器添加到以下ON条件的查询JOIN:
SELECT *
FROM Foo f
LEFT OUTER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId);
Run Code Online (Sandbox Code Playgroud)
是不一样放置过滤器的WHERE子句:
SELECT *
FROM Foo f
LEFT OUTER JOIN Bar b ON (b.BarId = f.BarId)
WHERE (b.IsApproved = 1);
Run Code Online (Sandbox Code Playgroud)
由于对"失败"外连接到Bar(即不存在b.BarId了f.BarId),这将离开b.IsApproved的NULL是所有这些失败的加入行,然后将这些行会被过滤掉.
另一种看待这种情况的方法是,对于第一个查询,LEFT OUTER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId)将始终返回LEFT表行,因为LEFT OUTER JOIN即使连接失败,也会保证返回LEFT表行.但是,添加(b.IsApproved = 1)到LEFT OUTER JOINon条件的效果是在(b.IsApproved = 1)false为false 时将任何右表列清空,即按照通常应用于LEFT JOIN条件的相同规则(b.BarId = f.BarId).
更新:要完成康拉德提出的问题,可选过滤器的等效LOJ将是:
SELECT *
FROM Foo f
LEFT OUTER JOIN Bar b ON (b.BarId = f.BarId)
WHERE (b.IsApproved IS NULL OR b.IsApproved = 1);
Run Code Online (Sandbox Code Playgroud)
ie该WHERE子句需要考虑连接失败(NULL)和过滤器是否被忽略的条件,以及连接成功和必须应用过滤器的条件.(b.IsApproved或b.BarId可以测试NULL)
我在这里放了一个SqlFiddle,它演示了b.IsApproved过滤器相对于过滤器的各个位置之间的差异JOIN.
aF.*_*aF. 30
不,查询优化器足够聪明,可以为两个示例选择相同的执行计划.
您可以使用SHOWPLAN检查执行计划.
但是,您应该将所有连接连接放在ON子句上以及对子句的所有限制WHERE.
SELECT * FROM Foo f
INNER JOIN Bar b ON b.BarId = f.BarId
WHERE b.IsApproved = 1;
Run Code Online (Sandbox Code Playgroud)
这是更好的形式.它易于阅读,易于修改.在商业世界中,这是您想要的.就性能而言,它们是相同的.