以下查询:
查询1:
SELECT * FROM DUAL
等同于并产生与:
相同的结果查询2:
SELECT * FROM DUAL
UNION
SELECT * FROM DUAL
在看到它们之前运行这两个查询之前,这是显而易见的。
然而,似乎Oracle并不理解这个非常简单的事实并产生两个不同的计划:
计划1:
Execution Plan
----------------------------------------------------------
Plan hash value: 272002086
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 2 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL| DUAL | 1 | 2 | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------
计划2:
Execution Plan
----------------------------------------------------------
Plan hash value: 646475286
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 4 | 6 (67)| 00:00:01 |
| 1 | SORT UNIQUE | | 2 | 4 | 6 (67)| 00:00:01 |
| 2 | UNION-ALL | | | | | |
| 3 | TABLE ACCESS FULL| DUAL | 1 | 2 | 2 (0)| 00:00:01 |
| 4 | TABLE ACCESS FULL| DUAL | 1 | 2 | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------
为什么?两个UNION编辑块的简单比较是否比执行UNION-ALL
和SORT UNIQUE
操作成本更低?或者有一种方法,一种暗示,迫使Oracle在这两种情况下生成相同的计划?
谢谢!
更新
Tnoy的回答迫使我做更多的实验。结果如下: 当查询与自身进行UNION编辑时,较大的查询不一定等同于原始查询。
例如,我创建了一个非常简单的test
表,该表只有一列,并且加载了两个相同的行。
现在,我对此表的第一个查询就是:
SELECT * FROM TEST
返回此结果:
A
-----
2
2
而我的UNION-ed查询:
SELECT * FROM TEST
UNION
SELECT * FROM TEST
返回此结果:
A
-----
2
这意味着Oracle优化器正在做正确的事情。
谢谢托尼!
答案 0 :(得分:3)
我不是Oracle开发人员,但我的猜测是数据库引擎必须“看到”所有行(UNION ALL
查询的结果),然后才能通过执行a来计算出有多少重复项独一无二的。
在你的问题的最后你说
...有没有办法,一个提示,迫使Oracle生成相同的计划 在这两种情况下?
我不这么认为,因为您正在尝试执行两个不同的查询。第一个查询是“表中的所有行”,第二个查询是要求“表中的所有唯一行”,
即使您没有任何重复项,数据库也不知道并且必须执行排序。
答案 1 :(得分:2)
对于查看查询的人来说,显而易见的事情对于优化器来说并不一定是显而易见的。
UNION
语句执行UNION ALL
后跟DISTINCT
。虽然数据库优化器可以搜索这种特殊情况(在完全相同的表之间进行联合的查询),但开发人员/经理必须对优先级做出决策。
在这种情况下识别优化可能是非常低的优先级。在您的特定示例中,执行计划可能不同,但两者基本上是即时的(除非您将在数百万个示例的循环中执行此操作)。