Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/83.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存在为什么选择rownum会导致执行计划效率低下?_Sql_Oracle_Exists_Query Performance_Rownum - Fatal编程技术网

SQL存在为什么选择rownum会导致执行计划效率低下?

SQL存在为什么选择rownum会导致执行计划效率低下?,sql,oracle,exists,query-performance,rownum,Sql,Oracle,Exists,Query Performance,Rownum,问题 我试图理解为什么这两个Oracle语法更新查询中的一个微小差异会导致完全不同的执行计划 问题1: UPDATE sales s SET status = 'DONE', trandate = sysdate WHERE EXISTS (Select * FROM tempTable tmp WHERE s.key1 = tmp.key1 AND s.key2 = tmp.key2 AND s.key3 = tmp.key3) 问题2

问题

我试图理解为什么这两个Oracle语法更新查询中的一个微小差异会导致完全不同的执行计划

问题1:

UPDATE sales s
   SET status = 'DONE', trandate = sysdate
 WHERE EXISTS (Select *    
 FROM tempTable tmp
     WHERE s.key1 = tmp.key1
       AND s.key2 = tmp.key2
       AND s.key3 = tmp.key3)
问题2:

UPDATE sales s
   SET status = 'DONE', trandate = sysdate
 WHERE EXISTS (Select rownum    
 FROM tempTable tmp
     WHERE s.key1 = tmp.key1
       AND s.key2 = tmp.key2
       AND s.key3 = tmp.key3)
正如您所看到的,两者之间的唯一区别是查询2中的子查询返回一个rownum,而不是每一行的值

这两个项目的执行计划完全不同:

  • Query1-从两个表中提取总结果,并使用排序和哈希连接返回结果。这种形式良好,代价为2346(尽管使用了EXISTS子句和内聚子查询)

  • Query2-同时提取两个表结果,但使用计数和筛选器来完成相同的任务,并返回一个执行计划,成本高达惊人的77789696!我应该注意到,他的查询只是挂在我的头上,所以我并不确定这会返回相同的结果(尽管我认为应该)

根据我对Exists子句的理解,它只是一个简单的布尔检查,在主表的每行运行。无论是以我的EXISTS条件返回一行还是返回100000行。。。如果为正在运行的行返回任何结果,则表示您已通过exist检查。那么,我的子查询SELECT语句返回什么又有什么关系呢

--------------编辑-----------------

根据请求,以下是我在TOAD中运行的执行计划。。。请注意,为了方便起见,我在上面的示例中编辑了表名-在这些计划中,ALSS_SALES2=sales above和SALESEXT_TMP=Dentiable above

也应该提到,但这两个表都没有索引。。我还没有将它们添加到我的诱惑中,我正在使用廉价的sales表副本进行测试,该表只包含字段和数据,但没有索引、约束或安全性

谢谢大家的帮助

查询1执行计划

查询2执行计划

--------------------------------------

问题

1) 为什么对rownum的调用会导致执行计划发生更改

2) 过滤器的什么地方效率如此之低


3) Exists子句的工作方式是否遗漏了导致此更改的基本要素?

发布实际的查询计划将非常有用

但是,通常情况下,当优化器看到子查询具有
rownum
时,会从根本上限制其转换查询和将子查询的结果与主查询合并的能力,因为这样做可能会影响结果。如果子查询恰好比优化器选择的计划更有效,那么这可能是迫使Oracle实现子查询的一种快速方法。不过,在这种情况下,它可能会导致优化器放弃转换步骤,从而使查询更高效

偶尔,你会看到有人接受这样的询问

SELECT b.*
  FROM (SELECT <<columns>>
          FROM driving_table
         WHERE <<conditions>>) a,
       b
 WHERE a.id = b.id
以强制优化器在执行联接之前计算
a
子查询。当然,通常情况下,如果优化器效率更高,优化器应该在默认情况下这样做。但是,如果优化器出错,添加
rownum
可能比找出正确的提示集来强制执行计划或深入底层问题以找到正确的解决方案要快


当然,在特定的情况下,您在
存在的地方有一个子查询,其中
rownum
的唯一用法出现在
SELECT
列表中,我们可以检测到
rownum
不应该阻止优化器想要使用的任何查询转换步骤。不过,优化器可能使用了一个更一般的规则,即引用函数
rownum
的子查询必须完全执行(这可能取决于Oracle的确切版本和/或优化器设置)。因此,优化器实际上在做大量额外的工作,因为它不够聪明,无法识别您添加的
rownum
不可能影响查询结果。

只是一个问题,此查询的执行计划是什么:

UPDATE sales s
   SET status = 'DONE', trandate = sysdate
 WHERE EXISTS (Select NULL
 FROM tempTable tmp
     WHERE s.key1 = tmp.key1
       AND s.key2 = tmp.key2
       AND s.key3 = tmp.key3);

它可视化了
存在(…)
表达式中需要的内容-实际上什么都没有!如前所述,Oracle只需检查是否返回了任何内容,而不是子查询中返回的内容

我的假设是,当您使用*时,引擎使用最相关的索引,但仅返回rownum可能会忽略该索引并执行顺序计划。但是我不确定你能不能包括执行计划,包括访问和过滤部分?谢谢Justin,这实际上很有意义,给了我很多关于rownum的好信息。我必须记住将rownum添加到子查询以尽早实现它的技巧。谢谢
UPDATE sales s
   SET status = 'DONE', trandate = sysdate
 WHERE EXISTS (Select NULL
 FROM tempTable tmp
     WHERE s.key1 = tmp.key1
       AND s.key2 = tmp.key2
       AND s.key3 = tmp.key3);