Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么SQL成本会随着简单的“或”而激增?_Sql_Performance_Oracle_Sqlperformance - Fatal编程技术网

为什么SQL成本会随着简单的“或”而激增?

为什么SQL成本会随着简单的“或”而激增?,sql,performance,oracle,sqlperformance,Sql,Performance,Oracle,Sqlperformance,我有以下声明,可以在我的数据中找到100万条明确的名称: 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 CON

我有以下声明,可以在我的数据中找到100万条明确的名称:

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
甲骨文显示了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

我的问题不是将其调整到最佳状态,因为它只是一个执行很少的查询,我知道CONTACT超过了任何索引,但我只是想知道这种高成本是从何而来的。这两个查询在语义上似乎与我相同。

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

EXISTS的操作与JOIN不同,本质上,OR filter语句是将表连接在一起的语句


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

两个查询的结果在语义上可能是等价的,但在操作上并不等价。第二个示例从不使用OR运算符组合谓词。第二个示例中的所有谓词都使用AND组合


性能更好,因为如果与AND组合的第一个谓词的计算结果不为true,则跳过第二个谓词或任何其他谓词,而不进行计算。如果使用OR,则必须频繁计算两个或所有谓词,从而降低查询速度。OR谓词被检查直到一个评估为true。

< P>我会考虑测试如下所述的重写查询。根据确定匹配条件的条件,从一个直接连接到另一个。。。然后,在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相同的结果,并给出最终结果


我将我的查询放回正常连接。

+1-详细说明一下,存在短路,或者不存在短路,至少在SQL Server中是这样,我假设Oracle与此类似。通过在EXISTS子项中包含OR,它每次都会检查这两个选项。分离意味着它仅在第一个为假时检查第二个。+1-执行计划1:筛选器不存在。。。1477315000 |索引ROWID的表访问人13863 |索引ROWID的表访问人4019;计划2非常庞大,使用了两个hash join,它们被接受为asnwer。我似乎高估了Oracle的查询分析器,因为它在语义上是等价的,我的意思是生成相同的结果集,我想他们会这样做…@stacktracer:good point。我将用类似“操作等效”的内容修改我的答案。虽然我不会假设不同查询的语义等价性。但我认为,在第二个示例中,通过省略或,您不仅更快,而且更安全。ORs会对结果造成严重破坏。这不是给了我一个模棱两可的名称吗?我更正了查询,以反映您指的是左外部联接,而不是联接。如果没有id为null,则使用联接可能不会返回任何结果。@stracktracer:在b.id为null的位置使用左联接b是执行“不存在”的巧妙方法。@stracktracer,@Benoit,请参阅修订后的注释返回到正常联接…正常联接不会给出任何结果。左外连接似乎有效,但持续时间为9秒,成本为195377045。