2011-03-25 47 views
2

例如,假设你有一个这样的查询:什么时候有利于约束SQL Server 2005中的连接?

SELECT * 
FROM table1 t1 
JOIN table2 t2 ON t1.field1 = t2.field1 AND t1.year = t2.year 
JOIN table3 t3 ON t1.field1 = t3.field1 AND t1.year = t3.year 
JOIN table4 t4 ON t3.field2 = t4.field2 AND t3.year = t4.year 
WHERE t1.year = '2010' 

它更快做到这一点:

SELECT * 
FROM table1 t1 
JOIN table2 t2 ON t1.field1 = t2.field1 AND t1.year = t2.year AND t2.year = '2010' 
JOIN table3 t3 ON t1.field1 = t3.field1 AND t1.year = t3.year AND t3.year = '2010' 
JOIN table4 t4 ON t3.field2 = t4.field2 AND t3.year = t4.year AND t4.year = '2010' 
WHERE t1.year = '2010' 

它并不总是显而易见的,这将是“快”。有时候,SQL Server 2005中的执行计划说一个比另一个快,这取决于索引。有时它会执行所有散列匹配,这看起来是CPU密集型的,而排序然后是合并连接似乎更加IO密集。考虑到执行计划的结果,真实世界的结果并不总是反映人们的期望。


有人能为我澄清一个比另一个更好的简单场景吗?或者至少验证我的理解是否正确?在我看来,如果你加入索引良好的列,那么不用限制一年或某些其他数据的连接会更有效,因为它可以使用基于索引的哈希匹配,并且不需要排序并使用临时表。但是,如果您在两个查询中选择并参与非索引列,那么添加时间约束会导致更少的行被处理,并导致更快的排序和合并连接,即使它引发了一些(更多? )IO成本。


而且,它困扰着我,从表2不考虑价值的有限的子集,从上表1 where子句中产生的预连接选择,它似乎从表2选择所有的行不使用时对连接的限制。由于table1中的行将会受到限制b WHERE t1.year ='2010'且连接受t1.year = t2.year限制,因此不应该认为连接只需要查看table2,其中year =' 2010' ?

我想知道为什么它没有先查看where子句,并且在连接之前只选择匹配的行,我相信这背后有一些很好的推理,但它逃脱了我,根据执行计划中,在这种情况下,从table2查看的行数会发生变化,具体取决于是否将t2.year ='2010'添加到连接中。

预先感谢您,对于长期的问题感到抱歉。我想尽可能清楚。请原谅我的缺乏经验。

+1

既然你问:“我不知道为什么它不看where子句第一“,我想我会告诉你逻辑查询处理顺序如下所示的信息:FROM(此步骤的一个子集创建基于连接和它们的ON筛选等的虚拟表),WHERE,GROUP BY ,HAVING,SELECT(这里的一部分步骤处理SELECT列表中的元素),然后ORDER BY被最后处理。 (还有几个子步骤我没有包括在内。) – 2011-03-28 13:23:50

回答

5

“它快吗?”编号

查询优化器将决定哪个是最严格的结果集筛选器(如果您的统计信息是最新的,通常会做得很好)。

+0

+1虽然它取决于确切的查询。即使在这种简单的情况下,也可以“欺骗”SQL Server(甚至是2008),甚至可以选择一些不好的计划......但是,大部分......是的。 – 2011-03-25 05:50:33

+0

我有一个查询,类似于上面,需要:50没有时间限制和:20与它一致。根据exec计划,差异似乎是一系列RID查找。任何有关这种情况的见解? (我知道这不是很好,因为我没有给你一个确切的例子,只是对可能性感到好奇。) – John 2011-03-25 10:11:21

+0

@John:我会发布执行计划 – 2011-03-25 11:03:24

1

有一个额外的过滤器不会增加任何值:优化器已经解决了。尽管如此,它使代码难以维护。

您可以OUTER做它加入,因为你不能在外部表的WHERE过滤器(更改的INNER JOIN):

SELECT * 
FROM table1 t1 
LEFT JOIN 
table2 t2 ON t1.field1 = t2.field1 AND t1.year = t2.year and t2.x = 1 
JOIN 
table3 t3 on t1.field1 = t3.field1 AND t1.year = t3.year 
... 
WHERE 
t1.year = '2010' 
+0

感谢它在外连接上有意义。 – John 2011-03-25 10:08:36