WHERE子句与ON时使用JOIN
假设我有以下T-SQL代码:
SELECT * FROM Foo f INNER JOIN Bar b ON b.BarId = f.BarId; WHERE b.IsApproved = 1;
下面的一个也返回相同的一组行:
SELECT * FROM Foo f INNER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId);
这可能不是最好的例子,但这两者之间有什么performance差异?
不,查询优化器足够聪明,可以为两个示例select相同的执行计划。
您可以使用SHOWPLAN
来检查执行计划。
不过,你应该把ON
子句的所有连接连接和WHERE
子句的所有限制放在一起。
只要注意与外连接的区别。 在JOIN
的ON
条件中添加b.IsApproved
的filter(在右表Bar上)的查询:
SELECT * FROM Foo f LEFT OUTER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId);
与将filter放置在WHERE
子句中不同:
SELECT * FROM Foo f LEFT OUTER JOIN Bar b ON (b.BarId = f.BarId) WHERE (b.IsApproved = 1);
因为对于'失败的'外连接到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)
,将(b.IsApproved = 1)
添加到LEFT OUTER JOIN
条件的效果是在(b.IsApproved = 1)
为假时根据通常应用于LEFT JOIN
条件(b.BarId = f.BarId)
。
更新 :要完成Conrad提出的问题,可选filter的等效LOJ将是:
SELECT * FROM Foo f LEFT OUTER JOIN Bar b ON (b.BarId = f.BarId) WHERE (b.IsApproved IS NULL OR b.IsApproved = 1);
即WHERE
子句需要考虑连接失败(NULL)
和filter是否被忽略的条件以及连接成功和filter必须被应用的情况。 ( b.IsApproved
或b.BarId
可以testingNULL
)
我已经把SqlFiddle放在一起,它演示了b.IsApproved
filter相对于JOIN
的不同位置之间的区别。
SELECT * FROM Foo f INNER JOIN Bar b ON b.BarId = f.BarId WHERE b.IsApproved = 1;
这是更好的forms去。 它易于阅读和易于修改。 在商业世界里,这是你想要的。 至于performance,他们是相同的。
我似乎有些情况下,即使在最新版本的MSSQL上,优化器也不够聪明 – 性能差异是怪物。
但是,这是一个例外,大部分时间SQL Server优化器将解决问题并获得正确的计划。
因此,保持在WHERE子句上使用filter的策略,并在需要时进行优化。
我只是对一个查询testing了四个表 – 一个主表有三个INNER JOIN和四个参数,并比较了两种方法的执行计划(在JOIN的ON中使用过滤条件,然后在WHERE子句)。
执行计划是完全一样的。 我在SQL Server 2008 R2上运行这个。