sql - 为什么使用 OR 条件而不是 Union 会导致性能问题

标签 sql sql-server union-all

您好,我在 SP 中有以下查询

@CrmContactId 是 SP 的参数。

Select distinct A.PolicyBusinessId, A.PolicyDetailId 
from TPolicyBusiness A
inner join TPolicyOwner B on a.PolicyDetailId=b.PolicyDetailId
Left Join TAdditionalOwner C on c.PolicyBusinessId=A.PolicyBusinessId
where (b.CRMContactId = @CRMContactId)  

我们做了一个新的改变,引入了一个 OR 条件

Select distinct A.PolicyBusinessId, A.PolicyDetailId 
from TPolicyBusiness A
inner join TPolicyOwner B on a.PolicyDetailId=b.PolicyDetailId
Left Join TAdditionalOwner C on c.PolicyBusinessId=A.PolicyBusinessId
where (b.CRMContactId = @CRMContactId OR C.CRMContactId = @CRMContactId) 

执行计划: enter image description here

附件:Execution Plan

但此更改在实时服务器中造成了巨大的性能问题。 TPolicyBusiness 和 TPolicyOwner 是拥有数百万条记录的大型表。 TAdditionalOwner 表是一个只有很少记录的轻型表。

要解决这个问题,Union all was 而不是 OR 条件。

Select distinct A.PolicyBusinessId, A.PolicyDetailId 
        From
        (
            Select A.PolicyBusinessId, A.PolicyDetailId 
            from TPolicyBusiness A
            inner join TPolicyOwner B on a.PolicyDetailId=b.PolicyDetailId
            where b.CRMContactId = @CRMContactId
            union all
            Select A.PolicyBusinessId, A.PolicyDetailId 
            from TPolicyBusiness A
            Join TAdditionalOwner C on c.PolicyBusinessId=A.PolicyBusinessId
            where C.CRMContactId = @CRMContactId
        ) as A

执行计划: enter image description here

附件 Execution Plan

谁能解释一下为什么引入 OR 会导致问题,以及为什么在这种情况下使用 Union 比 OR 更好?

最佳答案

使用UNION ALL 代替OR 实际上是众所周知的优化技巧之一。最好的引用和解释在这篇文章中:Index Union .

它的要点是 OR 谓词可以被两个索引查找满足不能被查询优化器可靠地检测到(原因是不可能预测OR 两侧的不相交集)。因此,当表达与 UNION ALL 相同的条件时,优化器可以毫无问题地创建执行两次短查找并将结果合并的计划。重要的是要意识到 a=1 or b=2 可以不同于 a=1 union all b=2 因为第一个查询返回满足 both 条件一次,而后者返回它们两次。当您将查询编写为 UNION ALL 时,您是在告诉编译器您理解这一点并且没有问题。

如需进一步引用,请参阅 How to analyse SQL Server performance .

关于sql - 为什么使用 OR 条件而不是 Union 会导致性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25520758/

相关文章:

mysql - MySQL UNION ALL 是如何运行聚合函数的?

SQLite数据库优化

sql - Postgres 中的快速近似计数

mysql - 选择最大列的值无法提供所需的结果

asp.net - 存储电话号码

sql-server - 如何将 SQL Server 数据库与我的 wpf 项目文件一起保存在光盘上

SQL查询以查找ID不在另一个表中的记录

c# - LINQ 查询返回第一个结果的多个副本

sql - SSIS Union All 不返回所有记录

mysql - UNION 结果集部分与单独的 SELECT 不同