在WHERE和ON子句上执行的顺序是什么?

时间:2013-12-11 14:43:57

标签: sql sql-server tsql

我正在阅读此页面关于APPLY:

http://sqlblog.com/blogs/alexander_kuznetsov/archive/2009/07/07/using-cross-apply-to-optimize-joins-on-between-conditions.aspx

我读了这篇关于逻辑查询处理的文章:

http://blog.sqlauthority.com/2009/04/06/sql-server-logical-query-processing-phases-order-of-statement-execution/

所以我可以理解这个查询需要很长时间。

SELECT s.StartedAt, s.EndedAt, c.AirTime 
FROM dbo.Commercials s JOIN dbo.Calls c  
  ON c.AirTime >= s.StartedAt AND c.AirTime < s.EndedAt 
WHERE c.AirTime BETWEEN '20080701' AND '20080701 03:00'

联接遍历所有行,然后 WHERE子句过滤结果。

但为什么这个查询闪电般快?

SELECT s.StartedAt, s.EndedAt, c.AirTime 
FROM dbo.Commercials s JOIN dbo.Calls c  
  ON c.AirTime >= s.StartedAt AND c.AirTime < s.EndedAt 
WHERE c.AirTime BETWEEN '20080701' AND '20080701 03:00' 
AND s.StartedAt BETWEEN '20080630 23:45' AND '20080701 03:00'

我知道WHERE子句正在过滤两个表的结果。但是这种过滤在JOIN之后发生,而在之前发生。现在如果它以某种方式实际发生在JOIN之前,那么我肯定明白为什么它如此之快。但是,如果我在第二个链接中使用L​​OE,则不应该是这种情况。正确?

4 个答案:

答案 0 :(得分:1)

这些查询没有明确的“之前”和“之后”。允许RDBMS决定何时运行查询的哪个部分,只要查询产生的结果不会改变。

在第一种情况下,查询无法预先过滤Commercials行,因为WHERE子句仅限制Calls的行。这些约束根据c.AirTime的相应行指定Commercials的范围,因此不可能进行预过滤:Calls的所有行都将考虑{{1}的每一行}}

然而,在第二种情况下,RDBMS可以通过观察您在2008年6月30日到2008年7月1日午夜之间将Commercials的范围限制在23:45之间来改善时间。限制c.AirTime加入s.StartedAt的{​​{1}}。这可以允许优化器使用索引(如果在c.AirTime列上定义了索引。

这里重要的观察是,在优化查询时,RDBMS可以做很聪明的事情。它通过应用多个逻辑规则来实现优化策略,尝试将约束推向更接近连接中的“行源”。检查优化器执行操作的最佳选择是读取查询计划。

答案 1 :(得分:0)

SQL Server Engine Optimizer中存在大量的逻辑,时间,血液,汗水和眼泪,这决定了确定语句实际处理方式的查询计划。在声明中写的内容绝不反映引擎中实际执行的内容。

要真正了解正在发生的情况,请启用show actual query plan选项运行查询。我的猜测是,基于额外的where子句,数据被优化器预过滤。

答案 2 :(得分:0)

它们不是相同的查询,所以为什么你会期望相同的响应时间

如果两个查询返回的行数不同,则使用top X进行更公平的比较

查询优化器可以变得非常智能(并且它可以变得愚蠢)
查看查询计划以查看正在进行的操作

我的经验是,如果您将条件提取到连接中,查询优化有更好的机会变得聪明

SELECT s.StartedAt, s.EndedAt, c.AirTime 
 FROM dbo.Commercials s 
 JOIN dbo.Calls c  
   ON c.AirTime >= s.StartedAt 
  AND c.AirTime < s.EndedAt 
  AND c.AirTime BETWEEN '20080701' AND '20080701 03:00' 
  AND s.StartedAt BETWEEN '20080630 23:45' AND '20080701 03:00'

如果您只有一个连接,那么查询优化器可能会提前移动到哪里 但是如果你有多个连接,我从未见过查询优化器提前移动

答案 3 :(得分:0)

第二个查询更快地限制了连接的范围。

第一个查询:加入B

第二个查询:连接子集(B)

作为子集(B)&lt; B本身扫描的匹配要少得多。

这导致了一个问题:该连接中使用的列有一个索引? (可能不是或速度不能相差很多)