Question

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!

Was it helpful?

Solution

I'm not an Oracle developer but my guess is the DB engine has to "see" all the rows (the result of a UNION ALL query) before it can work out how many duplicates there are by performing a unique sort.

At the end of your question you say

...is there a way, a hint, to force Oracle to generate the same plan in both cases?

I don't think so, since you are trying to perform two different queries. The first query is for "all rows in the table", your second query is asking for "all unique rows in the table",

Even if you don't have any duplicates the database doesn't know that and must perform a sort.

OTHER TIPS

What is obvious to a person looking at the queries is not necessarily obvious to the optimizer.

The UNION statement does a UNION ALL followed by a DISTINCT. Although the database optimizer could search for this particular case (a query that does a union between exactly the same tables), the developers/managers have to make decisions on priorities.

Identify the optimization in this case is presumably very low priority. In your particular example, the execution plans may be different but both are basically instantaneous (unless you are going to be doing this in a loop for millions of examples).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top