使用BETWEEN两个值指定的ON加速JOIN

时间:2015-01-16 13:56:32

标签: sql sql-server-2008 join

我很惊讶加入ON子句指定BETWEEN的两个表需要很长时间。在表A中,A.KeyUNIQUE,已排序ascending。在表B中,我们有B.KeyStartB.KeyEnd列也按升序排序,它们形成排除的区间,如1-4, 5-6, 7-11,依此类推。

SELECT A.Key, B.Column 
FROM tableA as A 
INNER JOIN  tableB as B
ON A.Key BETWEEN B.KeyStart AND B.KeyEnd

我该怎么做才能加快速度?

2 个答案:

答案 0 :(得分:1)

你可以试试的想法。如你所知,每个A只有B中的一个匹配,因为你知道范围不重叠,为什么要看KeyEnd呢?它始终是A记录的最大KeyStart B记录,其中B.KeyStart不大于A.Key。

所以我们得到A,在B中寻找最匹配的StartKey然后访问整个相应的B记录以便读取B.Column。您可以在此处使用SQL Server的CROSS APPLY。

select a.Key, b.Column
from tableA a
cross apply
( 
  select max(KeyStart) as KeyStart from tableB where tableB.KeyStart <= a.Key
) best
join tableB b on b.KeyStart = best.KeyStart;

这可能会更快。这可能会慢一点。试试吧。

SQL小提琴:http://www.sqlfiddle.com/#!3/58e44/3

答案 1 :(得分:0)

这主要比您预期的要慢,因为您希望DBMS知道它不知道的事情。

DBMS不知道没有重叠范围。因此,从DBMS的角度来看,甚至可能是所有B记录的范围从min Key到max Key,这意味着将所有A记录与所有B记录连接起来。只有你知道每张A记录只有一张B记录。

因此,DBMS必须通读所有B,以便找出匹配的内容和不匹配的内容。由于没有WHERE子句,所有记录都是相关的,因此使用索引是不可能的。

您可以通过它理解的约束告诉您所知的所有人,从而帮助DBMS:KeyStart是独一无二的。 KeyEnd是独一无二的。 (你不能说它没有重叠的范围。)也许它会有所帮助,但我实际上对此表示怀疑。

此外,您可以创建包含所有相关值的索引,因此无需读取表本身;将改为读取索引。 Index on tableB(KeyStart, KeyEnd, Column)