Oracle 11g: Another New Algorithm

Posted in: Technical Track

If you are or have ever been a SQL developer, it’s very likely you’ve been asked to return the rows from two joined tables, including all the rows from both tables that do not have a corresponding row in the other table. Oracle 9i introduced the FULL OUTER JOIN syntax to better address this scenario. Now it looks as if 11g has introduced a new algorithm to handle that.

So how can you get a look at this?

Step 1: Create a table

create table gark(col1 number);

Step 2: Write the query

select a.col1,b.col1
  from gark a full outer join gark b
   on a.col1=b.col1;

Step 3: Display the 11g plan

PLAN_TABLE_OUTPUT
----------------------------------------------------------
Plan hash value: 4017346954

----------------------------------------------------------
| Id  | Operation             | Name     | Rows  | Bytes |
----------------------------------------------------------
|   0 | SELECT STATEMENT      |          |     1 |    26 |
|   1 |  VIEW                 | VW_FOJ_0 |     1 |    26 |
|*  2 |   HASH JOIN FULL OUTER|          |     1 |    26 |
|   3 |    TABLE ACCESS FULL  | GARK     |       |       |
|   4 |    TABLE ACCESS FULL  | GARK     |     1 |    13 |
----------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("A"."COL1"="B"."COL1")

Note
-----
   - dynamic sampling used for this statement

It doesn’t look very impressive, except…

Step 4: Display the 10g plan

PLAN_TABLE_OUTPUT
-----------------------------------------------------
Plan hash value: 3812554007

-----------------------------------------------------
| Id  | Operation            | Name | Rows  | Bytes |
-----------------------------------------------------
|   0 | SELECT STATEMENT     |      |     2 |    52 |
|   1 |  VIEW                |      |     2 |    52 |
|   2 |   UNION-ALL          |      |       |       |
|*  3 |    HASH JOIN OUTER   |      |     1 |   104 |
|   4 |     TABLE ACCESS FULL| GARK |     1 |    65 |
|   5 |     TABLE ACCESS FULL| GARK |     1 |    39 |
|*  6 |    HASH JOIN ANTI    |      |     1 |    26 |
|   7 |     TABLE ACCESS FULL| GARK |     1 |    13 |
|   8 |     TABLE ACCESS FULL| GARK |     1 |    13 |
-----------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("A"."COL1"="B"."COL1"(+))
   6 - access("A"."COL1"="B"."COL1")

Note
-----
   - dynamic sampling used for this statement

One step further…

Looking at these two plans, I thought, “It’s obvious what Oracle changed and how they did it !” I thought I would illustrate the benefit of this new algorithm by raising the “TABLE ACCESS FULL” payload. To do that, you can change the table and data as below:

alter table gark add (col2 varchar2(1000));

begin
  for i in 1..100000 loop
     insert into gark values (i,lpad('$',999,'$'));
  end loop;
commit;
end;
/

exec dbms_stats.gather_table_stats(user,'GARK');

In my configuration, I’ve moved from ~62900 consistent gets (10.2.0.1) to ~34300 consistent gets (11.1.0.6). From this, you might think we know what happened behind the scenes. However, this simple test case shows up two additional differences. Obviously, nothing in Oracle works as simply as we imagine it does; and 11g is unlikely to change this one (and only?) optimizer rule. I’ll describe those two other changes in my next posts when I’ll be able to explain them.

email
Want to talk with an expert? Schedule a call with our team to get the conversation started.

No comments

Leave a Reply

Your email address will not be published. Required fields are marked *