Thursday, March 11, 2010

Index Skip Scan

Index Skip Scan were Introduced in Oracle 9i 

Index Skip Scan improves index scan by non-prefix columns.
Skip scanning splits the composite index to be logically split into smaller subindexes.
The number of logical Subindexes is determined by number of distinct values of Initial column.
Skip scanning is advantage if there are few distinct values in leading column and many distinct values on non-leading key columns.

create table t as select * from all_objects;
create index t_ind on t(object_type,object_id);
exec dbms_stats.gather_table_stats(ownname=>USER,tabname=>'T',estimate_percent=>100,cascade=>true,method_opt=>'for all columns size 254');

scott@10G> select object_type,count(*)
  2  from T
  3  group by object_type;

OBJECT_TYPE           COUNT(*)
-------------------            ----------
CONSUMER GROUP       2
INDEX PARTITION           446
JAVA DATA                     306
RULE                               7
SCHEDULE                     1
SEQUENCE                     227
TABLE PARTITION          298
OPERATOR                    57
PROCEDURE                 131
WINDOW                        2
LIBRARY                        152
LOB                                6
PACKAGE                      895
PACKAGE BODY           836
PROGRAM                     12
RULE SET                      26
CONTEXT                      5
JAVA RESOURCE          772
TYPE BODY                  176
XML SCHEMA                25
DIRECTORY                  5
JOB CLASS                   2
MATERIALIZED VIEW    2
TRIGGER                      261
FUNCTION                    294
INDEX                            2143
INDEXTYPE                   10
JAVA CLASS                 16420
SYNONYM                     20110
TABLE                           1948
VIEW                              3761
WINDOW GROUP          1
CLUSTER                       10
EVALUATION CONTEXT    14
JOB                                11
TYPE                            2013

36 rows selected.


So, splitting this Composite Index will result into 36 logical subindexes one for each object_type. 

scott@10G> select *
  2  from t
  3  where object_id between 100 and 200;

100 rows selected.

Elapsed: 00:00:00.03

-------------------------------------------------------------------------------------
| Id  | Operation                   | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |       |   100 |  9300 |   106   (1)| 00:00:02 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T     |   100 |  9300 |   106   (1)| 00:00:02 |
|*  2 |   INDEX SKIP SCAN           | T_IND |    99 |       |   101   (1)| 00:00:02 |
-------------------------------------------------------------------------------------

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

   2 - access("OBJECT_ID">=100 AND "OBJECT_ID"<=200)
       filter("OBJECT_ID"<=200 AND "OBJECT_ID">=100)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
         28  consistent gets
          0  physical reads
          0  redo size
       3890  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)
        100  rows processed

1 comment: