Dan*_*anK 7 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)
Run Code Online (Sandbox Code Playgroud)
查询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)
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,两者之间的唯一区别是查询2中的子查询返回rownum而不是每行的值.
这两者的执行计划不可能更加不同:
Query1 - 从两个表中提取总结果,并使用sort和hashjoin返回结果.这有利于2,346的成本(尽管使用了EXISTS条款和有凝聚力的子查询).
Query2 - 同时拉取两个表结果,但使用计数和过滤器来完成相同的任务,并以惊人的77,789,696成本返回执行计划!我应该注意到他的查询只是挂在我身上所以我实际上并不是肯定的,这会返回相同的结果(尽管我相信它应该).
根据我对Exists子句的理解,它只是一个简单的布尔检查,它运行在主表的每一行.如果在我的EXISTS条件中返回单行或100,000行也没关系...如果为正在运行的行返回任何结果,那么您已经通过了存在检查.那么为什么我的子查询SELECT语句返回的重要性呢?
- - - - - - - - - - 编辑 - - - - - - - - - - -
根据请求,下面是我在TOAD中运行的执行计划...请注意我在上面的示例中编辑了表名以方便 - 在这些计划中ALSS_SALES2 =销售额高于SALESEXT_TMP = tempTABLE.
还应该提到但是这两个表中都没有索引.我还没有将它们添加到我的tempTable中,我正在测试一个只包含字段和数据但没有索引的销售表的廉价副本,约束或安全.
感谢大家的帮助!
查询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
Run Code Online (Sandbox Code Playgroud)
并rownum指向a子查询
SELECT b.*
FROM (SELECT <<columns>>, rownum
FROM driving_table
WHERE <<conditions>>) a,
b
WHERE a.id = b.id
Run Code Online (Sandbox Code Playgroud)
为了强制优化器a在执行连接之前评估子查询.当然,通常情况下,如果效率更高,优化器应默认执行此操作.但是,如果优化器出错,那么添加rownum可能比找出正确的提示集更快,以迫使计划或深入挖掘底层问题以找出正确的解决方案.
当然,在你有一个子查询的具体情况WHERE EXISTS,其中唯一使用rownum自带的SELECT列表中,我们人类可以检测到rownum不应该阻止任何查询转换步骤,优化会照顾使用.但是,优化器可能正在使用更通用的规则,即rownum必须完全执行引用类似函数的子查询(这可能取决于确切的Oracle版本和/或优化器设置).因此,优化器实际上是在做一堆额外的工作,因为它不够聪明,无法识别rownum您添加的内容不会影响查询结果.