Showing posts with label Cardinality feedback in 11G. Show all posts
Showing posts with label Cardinality feedback in 11G. Show all posts

Thursday, December 9, 2010

Cardinality feedback in 11G

when you have a pipelined function - the estimated cardinality is computed based on your blocksize - the default number of rows that will come from it are based on your database block size. I have an 8k block size so..

rajesh@11GR2> create or replace function parse_list(p_varchar_list varchar2,p_delimiter in varcha
  2  return vcarray
  3  pipelined
  4  as
  5  begin
  6  for x in (      select
  7     trim( substr (txt,
  8     instr (txt, p_delimiter, 1, level  ) + 1,
  9     instr (txt, p_delimiter, 1, level+1)
 10     - instr (txt, p_delimiter, 1, level) -1 )
 11     )
 12     as discrete_value
 13     from   (select  p_delimiter||p_varchar_list||p_delimiter txt from dual)
 14     connect by level <= length(p_varchar_list)-length(replace(p_varchar_list,p_delimiter,'')
 15    loop
 16               pipe row(x.discrete_value);
 17    end loop;
 18  end;
 19  /

Function created.

Elapsed: 00:00:00.01
rajesh@11GR2>
rajesh@11GR2> variable x varchar2(40);
rajesh@11GR2> exec :x := 'A_B_C';

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00
rajesh@11GR2>
rajesh@11GR2>
rajesh@11GR2> set serveroutput off;
rajesh@11GR2>
rajesh@11GR2> select * from table ( cast( parse_list(:x,'_') as vcarray ) ) t;

COLUMN_VALUE
-------------
A
B
C

Elapsed: 00:00:00.01
rajesh@11GR2>
rajesh@11GR2> select * from table ( dbms_xplan.display_cursor );

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------
SQL_ID  2da7fr1xbuv36, child number 5
-------------------------------------
select * from table ( cast( parse_list(:x,'_') as vcarray ) ) t

Plan hash value: 58440541

------------------------------------------------------------------------------------------------
| Id  | Operation                         | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                  |            |       |       |    29 (100)|          |
|   1 |  COLLECTION ITERATOR PICKLER FETCH| PARSE_LIST |  8168 | 16336 |    29   (0)| 00:00:01 |
------------------------------------------------------------------------------------------------


13 rows selected.

The optimizer guesses 8168 rows. It all probability - the real number of rows is not anywhere near 8168. If we use this estimated row count in a bigger query - we'll probably end up with the wrong plan.


rajesh@11GR2>
rajesh@11GR2> select * from table ( cast( parse_list(:x,'_') as vcarray ) ) t;

COLUMN_VALUE
-------------
A
B
C

Elapsed: 00:00:00.00
rajesh@11GR2> select * from table ( dbms_xplan.display_cursor );

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------
SQL_ID  2da7fr1xbuv36, child number 6
-------------------------------------
select * from table ( cast( parse_list(:x,'_') as vcarray ) ) t

Plan hash value: 58440541

------------------------------------------------------------------------------------------------
| Id  | Operation                         | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                  |            |       |       |    29 (100)|          |
|   1 |  COLLECTION ITERATOR PICKLER FETCH| PARSE_LIST |     6 |    12 |    29   (0)| 00:00:01 |
------------------------------------------------------------------------------------------------

Note
-----
   - cardinality feedback used for this statement


17 rows selected.

Elapsed: 00:00:00.07
rajesh@11GR2>

 Apparently, now it hard parsed that query - it did not reuse the plan. We know that it hard parsed since it just created child #6 - and we can see the plan is different - the row count is much lower.


Now, in this example only the estimated row counts changed - The actual plan is same ( since the query is very simple ) will this affects real world application codes?


rajesh@11GR2> create table t
  2  nologging
  3  as
  4  select * from all_objects;

Table created.

Elapsed: 00:00:05.87
rajesh@11GR2>
rajesh@11GR2> create index t_ind on t
  2  ( case when owner = 'SCOTT' then owner
  3        when owner = 'APPQOSSYS' then owner
  4        when owner = 'OWBSYS' then owner
  5        else null end
  6  ) nologging;

Index created.

Elapsed: 00:00:00.48
rajesh@11GR2>
rajesh@11GR2> begin
  2     dbms_stats.gather_table_stats(
  3     ownname=>user,
  4     tabname=>'T',
  5     estimate_percent=>100,
  6     method_opt=>'for all columns size 254',
  7     cascade =>true);
  8  end;
  9  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:03.01
rajesh@11GR2>
rajesh@11GR2>
rajesh@11GR2> variable y varchar2(40);
rajesh@11GR2> exec :y := 'SCOTT_APPQOSSYS_OWBSYS';

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00
rajesh@11GR2>
rajesh@11GR2> with datas as
  2  (
  3    select * from table ( cast( parse_list(:y,'_') as vcarray ) )
  4  )
  5  select t.*
  6  from t , datas
  7  where case when owner ='SCOTT' then owner
  8             when owner ='APPQOSSYS' then owner
  9             when owner ='OWBSYS' then owner
 10             else null end  = datas.column_value;

 .....

11 rows selected.

Elapsed: 00:00:00.04
rajesh@11GR2>
rajesh@11GR2> select * from table ( dbms_xplan.display_cursor );

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------------------------------------
SQL_ID  6vy77gcct2fgy, child number 1
-------------------------------------
with datas as (   select * from table ( cast( parse_list(:y,'_') as
vcarray ) ) ) select t.* from t , datas where case when owner ='SCOTT'
then owner            when owner ='APPQOSSYS' then owner
when owner ='OWBSYS' then owner            else null end  =
datas.column_value

Plan hash value: 3303169200

--------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |            |       |       |  1002 (100)|          |
|   1 |  MERGE JOIN                         |            |   195M|    18G|  1002  (97)| 00:00:13 |
|   2 |   TABLE ACCESS BY INDEX ROWID       | T          | 71757 |  6867K|     5   (0)| 00:00:01 |
|   3 |    INDEX FULL SCAN                  | T_IND      |    11 |       |     1   (0)| 00:00:01 |
|*  4 |   SORT JOIN                         |            |  8168 | 16336 |    30   (4)| 00:00:01 |
|   5 |    COLLECTION ITERATOR PICKLER FETCH| PARSE_LIST |  8168 | 16336 |    29   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - access("T"."SYS_NC00016$"=VALUE(KOKBF$))
       filter("T"."SYS_NC00016$"=VALUE(KOKBF$))


27 rows selected.

Elapsed: 00:00:00.09


as opposed to


rajesh@11GR2> with datas as
  2  (
  3    select * from table ( cast( parse_list(:y,'_') as vcarray ) )
  4  )
  5  select t.*
  6  from t , datas
  7  where case when owner ='SCOTT' then owner
  8             when owner ='APPQOSSYS' then owner
  9             when owner ='OWBSYS' then owner
 10             else null end  = datas.column_value;

 .....

11 rows selected.

Elapsed: 00:00:00.12
rajesh@11GR2>
rajesh@11GR2> select * from table ( dbms_xplan.display_cursor );

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------------------------------------
SQL_ID  6vy77gcct2fgy, child number 2
-------------------------------------
with datas as (   select * from table ( cast( parse_list(:y,'_') as
vcarray ) ) ) select t.* from t , datas where case when owner ='SCOTT'
then owner            when owner ='APPQOSSYS' then owner
when owner ='OWBSYS' then owner            else null end  =
datas.column_value

Plan hash value: 4190747592

-------------------------------------------------------------------------------------------------
| Id  | Operation                          | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                   |            |       |       |    35 (100)|          |
|   1 |  NESTED LOOPS                      |            |    22 |  2200 |    35   (0)| 00:00:01 |
|   2 |   COLLECTION ITERATOR PICKLER FETCH| PARSE_LIST |     6 |    12 |    29   (0)| 00:00:01 |
|   3 |   TABLE ACCESS BY INDEX ROWID      | T          |     4 |   392 |     1   (0)| 00:00:01 |
|*  4 |    INDEX RANGE SCAN                | T_IND      |     1 |       |     0   (0)|          |
-------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - access("T"."SYS_NC00016$"=VALUE(KOKBF$))

Note
-----
   - cardinality feedback used for this statement


29 rows selected.

Elapsed: 00:00:00.10
rajesh@11GR2>