假设我们有
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)
由于
答案 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行),以达到很好的效果。