This query below:
Query 1:
SELECT * FROM DUAL
is equivalent to and produces the same result as:
Query 2:
SELECT * FROM DUAL
UNION
SELECT * FROM DUAL
This is obvious BEFORE running the two queries just by looking at them.
However, it seems Oracle doesn't understand this very simple fact and generates two different plans:
Plan 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 |
--------------------------------------------------------------------------
Plan 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 |
----------------------------------------------------------------------------
Why is that? Isn't a simple comparison of the two UNION-ed blocks less costly than doing both of the UNION-ALL
and SORT UNIQUE
operations? Or is there a way, a hint, to force Oracle to generate the same plan in both cases?
Thanks!
UPDATE
Tnoy's answer forced me to do some more experiments. Here is the result: When a query is UNION-ed with itself, the bigger query is not necessarily equivalent to the original query.
For example, I have created a very simple test
table having only one column and loaded with two identical rows.
Now, my first query on this table which is this:
SELECT * FROM TEST
returns this result:
A
-----
2
2
while my UNION-ed query of:
SELECT * FROM TEST
UNION
SELECT * FROM TEST
returns this result:
A
-----
2
which means the Oracle optimizer is doing the right thing.
Thanks Tony!