Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Union of a query with itself generates different plan

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!

like image 806
RGO Avatar asked Oct 15 '12 13:10

RGO


1 Answers

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.

like image 96
Tony Avatar answered Oct 11 '22 15:10

Tony