OR条件涉及多个表的性能不佳

时间:2012-04-02 20:03:57

标签: sql-server query-optimization

我有一个如下所示的查询:

SELECT *
FROM A
INNER JOIN B ON A.AId = B.AId
WHERE A.ADate BETWEEN @Start and @End
     or B.BDate BETWEEN @Start and @End

表A和B的大小大致相同,行数很多。执行计划显示索引搜索,但看起来它正在扫描整个索引。

如果我将or更改为and,则查询速度非常快。我认为这是因为如果不对两个表执行表扫描来计算or,就无法知道or的结果。 and很容易分成两个操作。

我读过一些人说可以使用UNION代替or,但如果OR中的两个条件都为真,这可能会引入重复行。

有什么解决方案可以减少连接的大小并阻止两个表的完全连接?我愿意重构查询但是可以使这个工作成为可能,但是需要查询的逻辑(给我一个项目,其中匹配范围的日期或B中的日期与范围匹配)保持不变。

3 个答案:

答案 0 :(得分:2)

如果在使用内联表加入之前对每个表进行预过滤呢?

SELECT A.*, B.*
FROM (SELECT AId AS Id FROM A WHERE A.ADate BETWEEN @Start and @End
      UNION
      SELECT BId AS Id FROM B WHERE B.BDate BETWEEN @Start and @End) AS FilteredIds
INNER JOIN A ON A.AId = FilteredIds.Id
INNER JOIN B ON B.BId = FilteredIds.Id

答案 1 :(得分:1)

UNION不会引入重复的行。 UNION ALL可能会引入重复项。

请参阅http://www.w3schools.com/sql/sql_union.asp

我想象:

SELECT *
FROM A
INNER JOIN B ON A.AId = B.AId
WHERE A.ADate BETWEEN @Start and @End

UNION

SELECT *
FROM A
INNER JOIN B ON A.AId = B.AId
WHERE B.BDate BETWEEN @Start and @End

可能是一个更快的查询。

答案 2 :(得分:0)

感谢您的回答,最后我选择UNION ALL,并根据两个相互排斥的选择的联合制作了一个查询,因此UNION ALL中不会引入任何重复项

首先,获取ADate在范围内的所有行,并排除BDate在范围内的行。然后获取BDate在范围内的所有行。这两个集合的联合在逻辑上产生了涵盖ADateBDate的行集,而没有重复计算中间值(因此UNION ALL不会产生重复项)。如果你看到这个逻辑中存在缺陷,请告诉我,我发现想到维恩图是有帮助的。

这使得查询执行了最好的选项(在我的情况下),并没有过于复杂,所以我选择了它。

SELECT *
FROM A
INNER JOIN B ON A.AId = B.AId
WHERE A.ADate BETWEEN @Start and @End
   and B.BDate NOT BETWEEN @Start and @End

UNION ALL

SELECT *
FROM A
INNER JOIN B ON A.AId = B.AId
WHERE B.BDate BETWEEN @Start and @End

在某些情况下,这可能是OR运算符的查询优化,尤其是在查询单独的大表时,它适用于日期范围,但可以与我想象的任何其他谓词一起使用。

相关问题