INNER JOIN与联接表上的位置

时间:2009-09-11 16:32:19

标签: sql sql-server tsql sql-server-2008

假设我们有 SELECT * FROM A INNER JOIN B ON [....]

假设A有2行而B包含1M行,其中2行链接到A
B只会扫描一次“实际行数”2对吗?

如果我在表WHERE上添加B
SELECT * FROM A INNER JOIN B ON [....] WHERE B.Xyz > 10

WHERE实际上会在加入之前执行...所以如果在哪里 返回1000行,B的“实际行数”将为1000 ... 我不明白..不应该是< = 2 ???

我错过了什么......为什么优化者会这样做? (SQL 2008)

由于

3 个答案:

答案 0 :(得分:2)

优化器将以其认为更快的方式继续进行。这意味着如果Xyz列被索引但连接列不是,它可能会首先执行xyz过滤器。或者,如果您的统计信息很糟糕,因此它不知道联接过滤器会将B减少到只有两行,它将首先执行WHERE子句。

答案 1 :(得分:1)

它完全基于可供优化器使用的索引。此外,没有理由相信db引擎将在查询的另一部分之前执行WHERE。只要返回正确的结果,查询优化器就可以按任何顺序自由执行查询。同样,正确优化此类查询的方法是使用策略性放置的索引。

答案 2 :(得分:0)

“仅扫描一次”有点误导。表扫描在SQL Server中是一件非常昂贵的事情。至少在SS2005之前,表扫描需要将所有行读入临时表,然后读取临时表以查找与连接条件匹配的行。因此,在最坏的情况下,您的查询将读取并写入 1M行,然后尝试将2行匹配到1M行,然后删除临时表(最后一位可能是查询中最便宜的部分) 。因此,如果B上没有可用的索引,那么你就处于一个糟糕的地方。

在你的第二个例子中,如果没有索引B.Xyz,则全表扫描发生从2行到1000行的次要匹配 - 效率更低。如果B.Xyz 索引,那么应该有索引查找和2:1000匹配 - 更快更好&更高效。

当然,这假设表统计信息是相对最新的,没有任何选项可以改变优化器的工作方式。

编辑:您是否有可能“展开”A行并将其用作B上无连接查询中的静态条件?我们已经在我们的应用程序中的几个地方使用了这个,我们将小表(<100行)连接到大(> 100M行),以达到很好的效果。