【发布时间】:2013-12-24 10:21:36
【问题描述】:
问题
我试图理解为什么这两个 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 - 从两个表中提取总结果并使用排序和哈希连接返回结果。这执行得很好,成本为 2,346(尽管使用了 EXISTS 子句和内聚子查询)。
Query2 - 同时提取两个表结果,但使用计数和过滤器来完成相同的任务,并返回一个执行计划,其成本高达惊人的 77,789,696!我应该注意到他的查询只是挂在我身上,所以我实际上并不肯定这会返回相同的结果(尽管我相信它应该)。
根据我对 Exists 子句的理解,它只是一个简单的布尔检查,在主表的每一行运行。如果在我的 EXISTS 条件中返回单行或 100,000 行,则无关紧要......如果它正在运行的行返回任何结果,那么您已经通过了存在检查。那么为什么我的子查询 SELECT 语句返回什么重要呢?
------------------编辑----------
根据请求,以下是我在 TOAD 中运行的执行计划...请注意,为方便起见,我在上面的示例中编辑了表名 - 在这些计划中 ALSS_SALES2 = 上面的销售额和 SALESEXT_TMP = 上面的 tempTABLE。
也应该提到,但此时这两个表都没有索引。我还没有将它们添加到我的 tempTable 中,我正在使用仅包含字段和数据的 sales 表的廉价副本进行测试但没有索引、约束或安全性。
感谢大家的帮助!
查询 1 执行计划
查询 2 执行计划
------------------------------------------ ----
问题
1) 为什么调用 rownum 会导致执行计划发生变化?
2) 过滤器效率如此之低的原因是什么?
3) 我是否遗漏了导致这种变化的 Exists 子句的工作方式的一些基本内容?
【问题讨论】:
-
我的假设是,当您使用 * 时,引擎使用最相关的索引但仅返回 rownum 可能会忽略索引并执行顺序计划。但我不确定
-
能否包括执行计划,包括访问和过滤部分?
标签: sql oracle exists query-performance rownum