微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么SQL成本会因简单的“或”而爆炸?

如何解决为什么SQL成本会因简单的“或”而爆炸?

| 我有以下语句可在我的数据中找到明确的名称(〜1百万个条目):
select Prename,Surname from person p1 
where Prename is not null and Surname is not null 
and not exists (
   select * from person p2 where (p1.Surname = p2.Surname OR p1.Surname = p2.Altname) 
   and p2.Prename LIKE CONCAT(CONCAT(\'%\',p1.Prename),\'%\') and p2.id <> p1.id
) and inv_date IS NULL
Oracle显示了1477315000的巨额成本,并且5分钟后执行不会停止。只需将OR拆分为一个现有的子条款,即可将性能提高到0.5 s,成本提高到45000:
select Prename,Surname from person p1 
where Prename is not null and Surname is not null 
and not exists (
   select * from person p2 where p1.Surname = p2.Surname and
   p2.Prename LIKE CONCAT(CONCAT(\'%\',\'%\') and p2.id <> p1.id
) and not exists (
   select * from person p2 where p1.Surname = p2.Altname and 
   p2.Prename LIKE CONCAT(CONCAT(\'%\',\'%\') and p2.id <> p1.id
) and inv_date IS NULL
将其调整到最佳状态不是我的问题,因为它只是很少执行的查询,而且我知道CONTACT超过了任何索引,但是我只是想知道这笔高成本是从哪里来的。这两个查询在语义上似乎与我相同。     

解决方法

答案在解释计划中供您查询。它们在语义上可能是等效的,但您查询的幕后执行计划大不相同。 EXISTS的操作不同于JOIN的操作,从本质上讲,您的OR过滤器语句是将表连接在一起的方法。 在第二个查询中没有JOIN发生,因为您仅从一个表中检索记录。     ,您的两个查询的结果在语义上可能是等效的,但是执行在操作上不是等效的。您的第二个示例从不使用OR运算符来组合谓词。第二个示例中的所有谓词都使用AND进行合并。 该性能更好,因为如果与AND组合的第一个谓词的求值不为true,则将跳过第二个(或任何其他谓词)(不求值)。如果您使用OR,则两个(或所有)谓词都必须经常进行评估,从而减慢查询速度。 (对ORed谓词进行检查,直到一个评估结果为true。)     ,我会考虑测试按以下方式重写的查询...按照“符合条件”(被视为匹配项)的标准从一个连接直接连接到另一个连接...然后,在WHERE子句中,将其丢弃没有提出比赛
select 
      p1.Prename,p1.Surname
   from 
      person p1 
         join person p2
            on p1.ID <> p2.ID
            and (  p1.Surname = p2.Surname
                or p1.SurName = p2.AltName )
            and p2.PreName like concat( concat( \'%\',p1.Prename ),\'%\' )
   where
          p1.PreName is not null
      and p1.SurName is not null
      and p1.Inv_date is null
      and p2.id is null
根据您的评论,但是从表面上看,您一直在寻找...不,请不要进行左外部联接...如果您要查找的名称类似于您想要清除的名称(但是您可以处理)那),您只想通过自联接(因此称为普通联接)来预先确定确实具有匹配的记录。如果您的名称没有相似的名称,则可能要保留它的名称...因此,它将自动被排除在结果集之外。 现在,WHERE子句开始...您在左边有一个有效的人...在右边有一个人..这些是重复项...因此,您有了匹配项,现在通过输入逻辑\ “ p2.ID IS NULL \”创建的结果与NOT EXIST给出的最终结果相同。 我将查询恢复为正常的“ join”。     

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。