Oracle之位图索引和多键索引区别

/*
总结“本质圆滑音其实就是位图索引之间的与非运算非常高效!
*/
总结:位图索引适合(与或非运算)男女、123等等,当存在位图索引时候,oracle会先去扫描位图索引列,然后依次向后进行扫描,然后会扫描前列。该例子聚合因子非常大、普通索引很慢。

---做位图索引与即席查询试验前的准备
drop table t purge;
set autotrace off
create table t 
(name_id,
 gender not null,
 location not null,
 age_group not null,
 data
 )
 as
 select rownum,
        decode(ceil(dbms_random.value(0,2)),
               1,'M',
               2,'F')gender,
        ceil(dbms_random.value(1,50)) location,
        decode(ceil(dbms_random.value(0,3)),
               1,'child',
               2,'young',
               3,'middle_age',
               4,'old'),
         rpad('*',400,'*')
from dual
connect by rownum<=100000;




---查询即席查询中应用全表扫描的代价
set linesize 1000
set autotrace traceonly
select *
    from t
    where gender='M'
    and location in (1,10,30)
    and age_group='child';


执行计划
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |   489 |   113K|  1674   (1)| 00:00:21 |
|*  1 |  TABLE ACCESS FULL| T    |   489 |   113K|  1674   (1)| 00:00:21 |
--------------------------------------------------------------------------
   1 - filter("GENDER"='M' AND ("LOCATION"=1 OR "LOCATION"=10 OR
              "LOCATION"=30) AND "AGE_GROUP"='child')
统计信息
----------------------------------------------------------
          0  recursive calls
          0  db block gets
       6112  consistent gets
          0  physical reads
          0  redo size
      15885  bytes sent via SQL*Net to client
        943  bytes received via SQL*Net from client
         50  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
        723  rows processed


-- 以下是即席查询中,Oracle选择组合索引情况的代价和逻辑读(注意,回表的代价特别大)。
drop index idx_union;
create index idx_union on t(gender,location,age_group);
--注意,以下收集统计信息必须先执行。
exec dbms_stats.gather_table_stats(ownname => user,tabname => 'T',estimate_percent => 10,method_opt=> 'for all indexed columns',cascade=>TRUE) ; 


select *
    from t
    where gender='M'
    and location in (1,10,30)
    and age_group='child';


普通联合索引执行计划
------------------------------------------------------------------------------------------
| Id  | Operation                    | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |           |   810 |   180K|   793   (0)| 00:00:10 |
|   1 |  INLIST ITERATOR             |           |       |       |            |          |
|   2 |   TABLE ACCESS BY INDEX ROWID| T         |   810 |   180K|   793   (0)| 00:00:10 |
|*  3 |    INDEX RANGE SCAN          | IDX_UNION |   810 |       |     4   (0)| 00:00:01 |
------------------------------------------------------------------------------------------
   3 - access("GENDER"='M' AND ("LOCATION"=1 OR "LOCATION"=10 OR "LOCATION"=30)
              AND "AGE_GROUP"='child')
统计信息
----------------------------------------------------------
          0  recursive calls
          0  db block gets
        1071  consistent gets
          0  physical reads
          0  redo size
     318987  bytes sent via SQL*Net to client
        943  bytes received via SQL*Net from client
         50  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
        731  rows processed


--- 即席查询应用到位图索引,性能有飞跃,ORACLE自己选择了使用位图索引
create bitmap index gender_idx on t(gender);
create bitmap index location_idx on t(location);
create bitmap index age_group_idx on t(age_group);
--注意,以下收集统计信息必须先执行。
exec dbms_stats.gather_table_stats(ownname => user,tabname => 'T',estimate_percent => 10,method_opt=> 'for all indexed columns',cascade=>TRUE) ; 


select *
    from t
    where gender='M'
    and location in (1,10,30)
    and age_group='child';


位图索引执行计划
-----------------------------------------------------------------------------------------------
| Id  | Operation                     | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |               |   810 |   180K|   236   (0)| 00:00:03 |
|   1 |  TABLE ACCESS BY INDEX ROWID  | T             |   810 |   180K|   236   (0)| 00:00:03 |
|   2 |   BITMAP CONVERSION TO ROWIDS |               |       |       |            |          |
|   3 |    BITMAP AND                 |               |       |       |            |          |
|   4 |     BITMAP OR                 |               |       |       |            |          |
|*  5 |      BITMAP INDEX SINGLE VALUE| LOCATION_IDX  |       |       |            |          |
|*  6 |      BITMAP INDEX SINGLE VALUE| LOCATION_IDX  |       |       |            |          |
|*  7 |      BITMAP INDEX SINGLE VALUE| LOCATION_IDX  |       |       |            |          |
|*  8 |     BITMAP INDEX SINGLE VALUE | AGE_GROUP_IDX |       |       |            |          |
|*  9 |     BITMAP INDEX SINGLE VALUE | GENDER_IDX    |       |       |            |          |
-----------------------------------------------------------------------------------------------
   5 - access("LOCATION"=1)
   6 - access("LOCATION"=10)
   7 - access("LOCATION"=30)
   8 - access("AGE_GROUP"='child')
   9 - access("GENDER"='M')
统计信息
----------------------------------------------------------
          0  recursive calls
          0  db block gets
        722  consistent gets
          0  physical reads
          0  redo size
     318987  bytes sent via SQL*Net to client
        943  bytes received via SQL*Net from client
         50  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
        731  rows processed

你可能感兴趣的:(Oracle之SQL优化章节)