Showing posts with label Good Bye to Cardinality Hint and Welcome to Cardinality Feedback. Show all posts
Showing posts with label Good Bye to Cardinality Hint and Welcome to Cardinality Feedback. Show all posts

Sunday, August 7, 2011

Good Bye to Cardinality Hint and Welcome to Cardinality Feedback

rajesh@ORA10GR2> create table t
  2  as
  3  select * from all_objects;

Table created.

Elapsed: 00:00:04.21
rajesh@ORA10GR2>
rajesh@ORA10GR2> create index t_ind on t(object_id) nologging;

Index created.

Elapsed: 00:00:00.32
rajesh@ORA10GR2>
rajesh@ORA10GR2> exec dbms_stats.gather_table_stats(user,'T');

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.42
rajesh@ORA10GR2>
rajesh@ORA10GR2>
rajesh@ORA10GR2> set autotrace traceonly explain statistics;
rajesh@ORA10GR2>
rajesh@ORA10GR2> select *
  2  from t
  3  where object_id in (select * from table ( sys.odcinumberlist(1,2,3,4,5,6) ) );

Elapsed: 00:00:00.07

Execution Plan
----------------------------------------------------------
Plan hash value: 1584247153
----------------------------------------------------------------------------
| Id  | Operation                              | Name | Rows  | Cost (%CPU)|
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT                       |      |     1 |   187   (4)|
|*  1 |  HASH JOIN RIGHT SEMI                  |      |     1 |   187   (4)|
|   2 |   COLLECTION ITERATOR CONSTRUCTOR FETCH|      |       |            |
|   3 |   TABLE ACCESS FULL                    | T    | 50096 |   161   (3)|
----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   1 - access("OBJECT_ID"=VALUE(KOKBF$))

Statistics
----------------------------------------------------------
        274  recursive calls
          0  db block gets
        797  consistent gets
          1  physical reads
          0  redo size
       1394  bytes sent via SQL*Net to client
        396  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
         21  sorts (memory)
          0  sorts (disk)
          5  rows processed

rajesh@ORA10GR2>

Optimizer is not using the index, since cardinality is not attached to plan at id=2, So how can we instruct the optimizer about cardinality?  using undocumented hint cardinality

rajesh@ORA10GR2> select *
  2  from t
  3  where object_id in (select /*+ cardinality(t,5) */ * from table ( sys.odcinumberlist(1,2,3,4,5,6) ) t  where rownum > 0);

Elapsed: 00:00:00.01

Execution Plan
----------------------------------------------------------
Plan hash value: 561482654
-------------------------------------------------------------------------------
| Id  | Operation                                   | Name     | Rows  | Cost  |
-------------------------------------------------------------------------------|
|   0 | SELECT STATEMENT                            |          |     1 |    27 |
|   1 |  TABLE ACCESS BY INDEX ROWID                | T        |     1 |     2 |
|   2 |   NESTED LOOPS                              |          |     1 |    27 |
|   3 |    VIEW                                     | VW_NSO_1 |     5 |    24 |
|   4 |     HASH UNIQUE                             |          |     1 |       |
|   5 |      COUNT                                  |          |       |       |
|*  6 |       FILTER                                |          |       |       |
|   7 |        COLLECTION ITERATOR CONSTRUCTOR FETCH|          |       |       |
|*  8 |    INDEX RANGE SCAN                         | T_IND    |     1 |     1 |
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   6 - filter(ROWNUM>0)
   8 - access("OBJECT_ID"="COLUMN_VALUE")

Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
         27  consistent gets
          0  physical reads
          0  redo size
       1388  bytes sent via SQL*Net to client
        396  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          5  rows processed

rajesh@ORA10GR2>
rajesh@ORA10GR2>


The predicate rownum > 0 is added to have the subquery "materialized".  Now we have the correct cardinality in plan & the optimizer picked up the index to answer our queries.

Even the MEMBER OF is not looking index at this point -- even when hinted to use index, it does Fast Full Scan and not Range scan.

rajesh@ORA10GR2> create or replace type numarray is table of number;
  2  /

Type created.

Elapsed: 00:00:00.06
rajesh@ORA10GR2>
rajesh@ORA10GR2> variable x refcursor;
rajesh@ORA10GR2>
rajesh@ORA10GR2> declare
  2     arr numarray := numarray(1,2,3,4,5,6);
  3  begin
  4     open :x for
  5     select object_id,data_object_id,owner,object_type,object_name
  6     from t
  7     where object_id member of ( arr );
  8  end;
  9  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00

SELECT OBJECT_ID,DATA_OBJECT_ID,OWNER,OBJECT_TYPE,OBJECT_NAME
FROM
 T WHERE OBJECT_ID MEMBER OF ( :B1 )

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.01       0.02          0          0          0           0
Fetch        1      0.04       0.03          0        694          0           5
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3      0.06       0.05          0        694          0           5

Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 61 

Rows     Row Source Operation
-------  ---------------------------------------------------
      5  TABLE ACCESS FULL T (cr=694 pr=0 pw=0 time=140 us)


rajesh@ORA10GR2>
rajesh@ORA10GR2> declare
  2     arr numarray := numarray(1,2,3,4,5,6);
  3  begin
  4     open :x for
  5     select /*+ index(t,t_ind) */ object_id,data_object_id,owner,object_type,object_name
  6     from t
  7     where object_id member of ( arr );
  8  end;
  9  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00
rajesh@ORA10GR2>

SELECT /*+ index(t,t_ind) */ OBJECT_ID,DATA_OBJECT_ID,OWNER,OBJECT_TYPE,
  OBJECT_NAME
FROM
 T WHERE OBJECT_ID MEMBER OF ( :B1 )

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.01       0.01          0          0          0           0
Fetch        1      0.03       0.03          0        113          0           5
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3      0.04       0.04          0        113          0           5

Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 61 

Rows     Row Source Operation
-------  ---------------------------------------------------
      5  TABLE ACCESS BY INDEX ROWID T (cr=113 pr=0 pw=0 time=97 us)
      5   INDEX FULL SCAN T_IND (cr=112 pr=0 pw=0 time=60 us)(object id 55213)


rajesh@ORA10GR2> declare
  2     arr numarray := numarray(1,2,3,4,5,6);
  3  begin
  4     open :x for
  5     select object_id,data_object_id,owner,object_type,object_name
  6     from t
  7     where object_id in ( select /*+ cardinality(t1,5) */ * from table ( arr ) t1 ) ;
  8  end;
  9  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.03
rajesh@ORA10GR2>

SELECT OBJECT_ID,DATA_OBJECT_ID,OWNER,OBJECT_TYPE,OBJECT_NAME
FROM
 T WHERE OBJECT_ID IN ( SELECT /*+ cardinality(t1,5) */ * FROM TABLE ( :B1 )
  T1 )

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          9          0           0
Fetch        1      0.00       0.00          0          9          0           5
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3      0.00       0.00          0         18          0           5

Misses in library cache during parse: 1
Misses in library cache during execute: 1
Optimizer mode: ALL_ROWS
Parsing user id: 61 

Rows     Row Source Operation
-------  ---------------------------------------------------
      5  TABLE ACCESS BY INDEX ROWID T (cr=9 pr=0 pw=0 time=278 us)
     12   NESTED LOOPS  (cr=8 pr=0 pw=0 time=889 us)
      6    SORT UNIQUE (cr=0 pr=0 pw=0 time=92 us)
      6     COLLECTION ITERATOR PICKLER FETCH (cr=0 pr=0 pw=0 time=28 us)
      5    INDEX RANGE SCAN T_IND (cr=8 pr=0 pw=0 time=93 us)(object id 55213)


When working with Oracle 10g database, we need to Instruct cardinality to optimizer using Cardinality Hint. But when repeating the same test in Oracle 11g database

rajesh@ORA11GR2>
rajesh@ORA11GR2> select object_id,data_object_id,owner,object_type,object_name
  2  from t
  3  where object_id in (select * from table ( sys.odcinumberlist(1,2,3,4,5,6) ) );

 OBJECT_ID DATA_OBJECT_ID OWNER      OBJECT_TYPE     OBJECT_NAME
---------- -------------- ---------- --------------- --------------------
         3              3 SYS        INDEX           I_OBJ#
         6              6 SYS        CLUSTER         C_TS#
         5              2 SYS        TABLE           CLU$
         2              2 SYS        CLUSTER         C_OBJ#
         4              2 SYS        TABLE           TAB$

Elapsed: 00:00:00.07
rajesh@ORA11GR2>

select object_id,data_object_id,owner,object_type,object_name
from t
where object_id in (select * from table ( sys.odcinumberlist(1,2,3,4,5,6) ) )

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      0.03       0.02          0       1026          0           5
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.03       0.02          0       1026          0           5

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 91 

Rows     Row Source Operation
-------  ---------------------------------------------------
      5  HASH JOIN RIGHT SEMI (cr=1026 pr=0 pw=0 time=0 us cost=316 size=49 card=1)
      6   COLLECTION ITERATOR CONSTRUCTOR FETCH (cr=0 pr=0 pw=0 time=5 us cost=29 size=16336 card=8168)
  71598   TABLE ACCESS FULL T (cr=1026 pr=0 pw=0 time=99596 us cost=286 size=3365106 card=71598)

rajesh@ORA11GR2> select object_id,data_object_id,owner,object_type,object_name
  2  from t
  3  where object_id in (select * from table ( sys.odcinumberlist(1,2,3,4,5,6) ) );

OBJECT_ID DATA_OBJECT_ID OWNER      OBJECT_TYPE     OBJECT_NAME
---------- -------------- ---------- --------------- --------------------
         2              2 SYS        CLUSTER         C_OBJ#
         3              3 SYS        INDEX           I_OBJ#
         4              2 SYS        TABLE           TAB$
         5              2 SYS        TABLE           CLU$
         6              6 SYS        CLUSTER         C_TS#

Elapsed: 00:00:00.04
rajesh@ORA11GR2>

select object_id,data_object_id,owner,object_type,object_name
from t
where object_id in (select * from table ( sys.odcinumberlist(1,2,3,4,5,6) ) )

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      0.00       0.00          0         12          0           5
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.00       0.00          0         12          0           5

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 91 

Rows     Row Source Operation
-------  ---------------------------------------------------
      5  NESTED LOOPS  (cr=12 pr=0 pw=0 time=0 us)
      5   NESTED LOOPS  (cr=10 pr=0 pw=0 time=136 us cost=36 size=294 card=6)
      6    SORT UNIQUE (cr=0 pr=0 pw=0 time=5 us cost=29 size=12 card=6)
      6     COLLECTION ITERATOR CONSTRUCTOR FETCH (cr=0 pr=0 pw=0 time=5 us cost=29 size=12 card=6)
      5    INDEX RANGE SCAN T_IND (cr=10 pr=0 pw=0 time=0 us cost=1 size=0 card=1)(object id 79427)
      5   TABLE ACCESS BY INDEX ROWID T (cr=2 pr=0 pw=0 time=0 us cost=2 size=47 card=1)


You see the optimizer hard parsed the query again & came up with right explain plan to answer this query. And further execution optimizer has reused the plan again.

rajesh@ORA11GR2> select object_id,data_object_id,owner,object_type,object_name
  2  from t
  3  where object_id in (select * from table ( sys.odcinumberlist(1,2,3,4,5,6) ) );

 OBJECT_ID DATA_OBJECT_ID OWNER      OBJECT_TYPE     OBJECT_NAME
---------- -------------- ---------- --------------- --------------------
         2              2 SYS        CLUSTER         C_OBJ#
         3              3 SYS        INDEX           I_OBJ#
         4              2 SYS        TABLE           TAB$
         5              2 SYS        TABLE           CLU$
         6              6 SYS        CLUSTER         C_TS#

Elapsed: 00:00:00.03
rajesh@ORA11GR2>

select object_id,data_object_id,owner,object_type,object_name
from t
where object_id in (select * from table ( sys.odcinumberlist(1,2,3,4,5,6) ) )

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      0.00       0.00          0         12          0           5
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.00       0.00          0         12          0           5

Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 91 

Rows     Row Source Operation
-------  ---------------------------------------------------
      5  NESTED LOOPS  (cr=12 pr=0 pw=0 time=0 us)
      5   NESTED LOOPS  (cr=10 pr=0 pw=0 time=120 us cost=36 size=294 card=6)
      6    SORT UNIQUE (cr=0 pr=0 pw=0 time=5 us cost=29 size=12 card=6)
      6     COLLECTION ITERATOR CONSTRUCTOR FETCH (cr=0 pr=0 pw=0 time=10 us cost=29 size=12 card=6)
      5    INDEX RANGE SCAN T_IND (cr=10 pr=0 pw=0 time=0 us cost=1 size=0 card=1)(object id 79427)
      5   TABLE ACCESS BY INDEX ROWID T (cr=2 pr=0 pw=0 time=0 us cost=2 size=47 card=1)


This proper cardinality is supplied to 11g optimizer by a new feature "cardinality feedback