bitmap index 适用于 dss(决策支持系统) 和Data warehouse,ORACLE 建议的是不要在繁重的OLTP中使用 bitmap index ,我
个人建议:千万别在OLTP中使用bitmap index,否则你死定了。
请看一下测试:
SQL> create table test as select * from dba_objects;
表已创建。
SQL> update test set status='INVALID' where owner='SCOTT';
已更新13行。
SQL> commit;
提交完成。
SQL> exec dbms_stats.gather_table_stats('ROBINSON','TEST');
PL/SQL 过程已成功完成。
SQL> create bitmap index i_b_stats on test(status);
索引已创建。
SQL> select count(*) from test where status='INVALID';
COUNT(*)
----------
14
执行计划
----------------------------------------------------------
Plan hash value: 148891143
-----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 7 | 1 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 7 | | |
| 2 | BITMAP CONVERSION COUNT | | 24981 | 170K| 1 (0)| 00:00:01 |
|* 3 | BITMAP INDEX SINGLE VALUE| I_B_STATS | | | | |
-----------------------------------------------------------------------------------------
SQL> drop index i_b_stats ;
索引已删除。
SQL> exec dbms_stats.gather_table_stats('ROBINSON','TEST',method_opt=>'for columns size 10 status');
PL/SQL 过程已成功完成。
SQL> select count(*) from test where status='INVALID';
COUNT(*)
----------
14
执行计划
----------------------------------------------------------
Plan hash value: 680875269
------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 7 | 1 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 7 | | |
|* 2 | INDEX RANGE SCAN| I_STATUS | 8 | 56 | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------
SQL> select count(*) from test where status='VALID';
COUNT(*)
----------
49947
执行计划
----------------------------------------------------------
Plan hash value: 1531502959
----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 7 | 27 (8)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 7 | | |
|* 2 | INDEX FAST FULL SCAN| I_STATUS | 49948 | 341K| 27 (8)| 00:00:01 |
----------------------------------------------------------------------------------
SQL> drop index i_status ;
索引已删除。
SQL> create bitmap index i_b_status on test(status);
索引已创建。
SQL> select count(*) from test where status='VALID';
COUNT(*)
----------
49947
执行计划
----------------------------------------------------------
Plan hash value: 1410402464
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 7 | 2 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 7 | | |
| 2 | BITMAP CONVERSION COUNT | | 49948 | 341K| 2 (0)| 00:00:01 |
|* 3 | BITMAP INDEX FAST FULL SCAN| I_B_STATUS | | | | |
--------------------------------------------------------------------------------------------
可以看到bitmap(cost=2)的查询效率确实比B*tree(cost=27)效率高很多。
现在我们来看看bitmap对于DML的影响。
在三个session中同时执行
insert into test select * from dba_objects where rownum<2;
我这里就不贴了,我们看看ASH,看看v$session_wait,v$session.
SQL> select sid,username,program,event from v$session where username is not null;
SID USERNAME PROGRAM EVENT
---------- ------------------------------ ---------------------------------------------------------------- ----------------------------------------------------------------
143 ROBINSON plsqldev.exe SQL*Net message from client
144 ROBINSON plsqldev.exe enq: TX - row lock contention
146 ROBINSON plsqldev.exe SQL*Net message from client
159 ROBINSON sqlplus.exe enq: TX - row lock contention
可以看到在sqlplus,plsqldev中分别发生了TX-row lock contention竞争,这个竞争就是由于刚才执行的
insert into test select * from dba_objects where rownum<2;引起的。
如果你不相信,我用ASH给你查找出来
SQL> select session_id,event,count(*),sum(time_waited) from v$active_session_history where session_state='WAITING'
2 and time_waited>0 and sample_time>=(sysdate-&howlongago/(24*60))
3 group by session_id,event order by 3 desc;
SESSION_ID EVENT COUNT(*) SUM(TIME_WAITED)
---------- ---------------------------------------------------------------- ---------- ----------------
144 enq: TX - row lock contention 146 435563478
159 enq: TX - row lock contention 138 414017496
167 db file parallel write 7 64316
165 control file parallel write 5 63539
143 enq: TX - row lock contention 4 10362621
166 log file parallel write 2 133521
165 control file sequential read 1 86807
164 db file sequential read 1 26782
146 db file sequential read 1 572
9 rows selected
SQL> select event, session_id,sql_id, p1,p2,p3 from v$active_session_history where sample_time>=(sysdate-&howlongago/(24*60)) and session_id=&sid;
EVENT SESSION_ID SQL_ID P1 P2 P3
---------------------------------------------------------------- ---------- ------------- ---------- ---------- ----------
enq: TX - row lock contention 144 9n78yftyyayk1 1415053316 196632 978
enq: TX - row lock contention 144 9n78yftyyayk1 1415053316 196632 978
enq: TX - row lock contention 144 9n78yftyyayk1 1415053316 196632 978
............................................................................省略.....................................................................
498 rows selected
ASH 是 每隔1s收集一次统计信息,我这里查询除了498条,意思就是说等待了498秒,而且现在还在等待,我估计我不kill其中的一个session
永远都,那么那两个会话将永远等待。
SQL> select sql_text from v$sqlarea where sql_id='&sql_id';
SQL_TEXT
--------------------------------------------------------------------------------
insert into test select * from dba_objects where rownum<2
由此证明,引起TX-row lock contention就是 上面的那条insert语句.
此时你除了kill其中一个session,别无办法。
只有2,3个人并发的去操作某一个表,就发生了TX lock,如果并发再高点,估计整个表都无法用,在刚才那张表中,由于status只有valid和invalid两个值,当一条insert 执行的时候,如果status是valid的,由于要更新bitmap,需要lock status=valid的所有行,所以千万别在oltp中使用bitmap index 。