为什么SQL成本会以简单的"或"爆炸?

str*_*cer 7 sql oracle performance sqlperformance

我有以下声明在我的数据中找到明确的名称(约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
Run Code Online (Sandbox Code Playgroud)

Oracle显示1477315000的巨额成本,并且执行不会在5分钟后结束.简单地将OR分成一个自己存在的子条款将性能提升到0.5秒,成本增加到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('%', p1.Prename), '%') and p2.id <> p1.id
) and not exists (
   select * from person p2 where p1.Surname = p2.Altname and 
   p2.Prename LIKE CONCAT(CONCAT('%', p1.Prename), '%') and p2.id <> p1.id
) and inv_date IS NULL
Run Code Online (Sandbox Code Playgroud)

把问题调整到最好是不是我的问题,因为它只是一个很少执行的查询,我知道CONTACT超过了任何索引,但我只是想知道这个高成本来自哪里.两个查询在语义上都与我相当.

map*_*aft 6

答案在EXPLAIN PLAN中供您查询.它们在语义上可能是等价的,但是查询的幕后执行计划却大不相同.

EXISTS的操作与JOIN的操作不同,实质上,您的OR过滤器语句将表连接在一起.

第二个查询中没有JOIN,因为您只从一个表中检索记录.

  • +1 - 详细说明,`EXISTS`短路和`OR`没有(至少在SQL Server中,我假设Oracle类似).通过在`EXISTS`子中包含`OR`,它每次都检查两个选项.分离意味着它只检查第二个是否第一个是假的. (3认同)
  • +1 - 执行计划1:过滤器不存在(...)1477315000 | 表访问人员索引ROWID 13863 | 表格访问人员索引ROWID 4019; 计划2很庞大,使用两个散列连接 (2认同)