/*
总结“本质圆滑音其实就是位图索引之间的与非运算非常高效!
*/
总结:位图索引适合(与或非运算)男女、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