查询与其自身的联合生成不同的计划

RGO*_*RGO 5 sql oracle query-optimization union-all

这个查询如下:

查询1:

SELECT * FROM DUAL 
Run Code Online (Sandbox Code Playgroud)

相当于并产生与以下相同的结果:

查询2:

SELECT * FROM DUAL 
UNION
SELECT * FROM DUAL
Run Code Online (Sandbox Code Playgroud)

在通过查看它们运行两个查询之前,这是显而易见的.

但是,似乎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 |
--------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

计划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 |
----------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

这是为什么?两个UNION编辑的块的简单比较不是比执行这两个块UNION-ALLSORT UNIQUE操作更便宜吗?或者有一种方法,一种暗示,迫使Oracle在这两种情况下生成相同的计划?

谢谢!

UPDATE

Tnoy的回答迫使我做了一些实验.结果如下: 当查询与自身进行UNION编辑时,较大的查询不一定等同于原始查询.

例如,我创建了一个非常简单的test表,只有一列,并加载了两个相同的行.

现在,我对此表的第一个查询是:

SELECT * FROM TEST 
Run Code Online (Sandbox Code Playgroud)

返回此结果:

  A
-----
  2
  2
Run Code Online (Sandbox Code Playgroud)

而我的UNION-ed查询:

SELECT * FROM TEST
UNION
SELECT * FROM TEST
Run Code Online (Sandbox Code Playgroud)

返回此结果:

  A
-----
  2
Run Code Online (Sandbox Code Playgroud)

这意味着Oracle优化器正在做正确的事情.

谢谢托尼!

Ton*_*ony 3

我不是 Oracle 开发人员,但我的猜测是数据库引擎必须“查看”所有行(查询的结果UNION ALL),然后才能通过执行唯一排序来计算出有多少重复项。

在你的问题的最后你说

...有没有一种方法、提示可以强制 Oracle 在两种情况下生成相同的计划?

我不这么认为,因为您正在尝试执行两个不同的查询。第一个查询是“表中的所有行”,第二个查询是要求“表中的所有唯一行”,

即使您没有任何重复项,数据库也不知道这一点,并且必须执行排序。