[20150204]关于位图索引4.txt
--许多人知道在oltp系统不适合使用位图索引.它的索引的记录结构如下是:
字段0:键值
字段1:开始rowid
字段2:结束rowid
字段3:位图信息,指示那行记录,位图1=>表示存在.位图0=>表示不存在.
--但是字段4的位图信息,介绍的资料太少,我自己看了链接http://juliandyke.com/Presentations/BitmapIndexInternals.ppt,做一个简单探究.
--前面的讲解仅仅在1个数据块的情况,如果开始rowid与结束rowid在不同数据块的情况呢?自己再做一些验证.
--在验证前我讲一下Hakan Factor:
. Hakan Factor can be adjusted using
ALTER TABLE table_name MINIMIZE RECORDS_PER_BLOCK;
. This command
. Scans entire table
. Counts number of rows in each block
. Sets Hakan Factor in SPARE1 to maximum row count
. Sets bit 0x8000 in SPARE1 to indicate value has been set
. Subsequently modified blocks will be limited to the new Hakan Factor
. Command is reversed using
ALTER TABLE table_name NOMINIMIZE RECORDS_PER_BLOCK;
--Hakan Factor 概括讲就是设置1个块能插入的最大行号(也限制了插入行记录的数量).信息保存在sys.tab$的spare1字段中,等于
--0x8000+记录最大行号.使用它最大好处:
Hakan Factor
. Hakan Factor is used when compressing bitmaps
. Each bitmap represents an array Blocks
Maximum rows per block
. Minimising records per block reduces size of this array Blocks Maximum rows per block
. Reduces memory required to access/manipulate bitmap
. May reduce disk space required to hold bitmap
--实际上使用它可以位图信息大小,减少磁盘空间占用.实际上我以前自己测试过,减少的量可以讲很少,因为位图编码可以压缩许多信息.
--总之使用它效果不是很明显,但是那它来控制1块插入的记录数,控制发生行迁移的情况倒是一个不错的选择.
--先测试使用Hakan Factor的情况:
1.建立测试环境:
SCOTT@test> @ver1
PORT_STRING VERSION BANNER
------------------------------ -------------- --------------------------------------------------------------------------------
x86_64/Linux 2.4.xx 11.2.0.3.0 Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
--drop table t purge;
create table t(id number , name varchar2(10), status varchar2(1));
insert into t select rownum-1 id,dbms_random.string('X',10) c20,decode(mod((rownum-1),8),0,'Y','N') c1 from dual connect by levelcommit ;
alter table t minimize records_per_block;
insert into t select 66+rownum-1 id,dbms_random.string('X',10) c20,decode(mod((rownum-1),8),1,'Y','N') c1 from dual connect by levelcommit;
create bitmap index ib_t_status on t(status);
SCOTT@test> select rowid,t.* from t where id=0 or id=66;
ROWID ID NAME S
------------------ ---------- -------------------- -
AABI+7AAEAAAACjAAA 66 5AUDMDRUO4 N
AABI+7AAEAAAACnAAA 0 DXMRIJ3Y7X Y
SCOTT@test> @lookup_rowid AABI+7AAEAAAACjAAA
OBJECT FILE BLOCK ROW DBA TEXT
---------- ---------- ---------- ---------- -------------------- ----------------------------------------
298939 4 163 0 4,163 alter system dump datafile 4 block 163 ;
SCOTT@test> @lookup_rowid AABI+7AAEAAAACnAAA
OBJECT FILE BLOCK ROW DBA TEXT
---------- ---------- ---------- ---------- -------------------- ----------------------------------------
298939 4 167 0 4,167 alter system dump datafile 4 block 167 ;
SCOTT@test> select owner,segment_name,header_file,header_block from dba_segments where owner=user and segment_name='IB_T_STATUS';
OWNER SEGMENT_NAME HEADER_FILE HEADER_BLOCK
------ -------------------- ----------- ------------
SCOTT IB_T_STATUS 4 530
SCOTT@test> select spare1 from sys.tab$ where obj#=298939;
SPARE1
----------
32833
SCOTT@test> select 32833-32768 from dual;
32833-32768
-----------
65
--可以发现复合前面的设置.
SCOTT@test> alter system checkpoint ;
System altered.
SCOTT@test> alter system dump datafile 4 block 531 ;
System altered.
row#0[7992] flag: ------, lock: 0, len=40
col 0; len 1; (1): 4e
col 1; len 6; (6): 01 00 00 a3 00 00
col 2; len 6; (6): 01 00 00 a7 00 47
col 3; len 21; (21):
cf fd fd fd fd fd fd fd fd 00 ff 15 fe fe fe fe fe fe fe fe 01
row#1[7952] flag: ------, lock: 0, len=40
col 0; len 1; (1): 59
col 1; len 6; (6): 01 00 00 a3 00 00
col 2; len 6; (6): 01 00 00 a7 00 47
col 3; len 21; (21):
cf 02 02 02 02 02 02 02 02 01 ff 15 01 01 01 01 01 01 01 01 00
----- end of leaf block dump -----
End dump data blocks tsn: 4 file#: 4 minblk 531 maxblk 531
--还是拿status='Y'的col3来说明:
--01 00 00 a3, 对应是dba是4,163.
--01 00 00 a7, 对应是dba是4,167.
SCOTT@test> @dfb 010000a7
RFILE# BLOCK#
---------- ----------
4 167
-- cf 02 02 02 02 02 02 02 02 01 ff 15 01 01 01 01 01 01 01 01 00
-- cf 拆开:
-- 11 001 111
-- 11 大于192.表示Multi-Byte Groups
-- 001 表示 0个字节0
-- 111 表示8个字节长度.
-- 这个块4,163,id>=66,我设置是第2位是status='Y',这样后面的02就对上了.
-- 注意后面还有1个01,这个前面讲的单字节组,表示01000000,也就是这个8位的第2位,id就是 66+64+2-1=131.
SCOTT@test> select * from t where status='Y' and id>=66;
ID NAME S
---------- -------------------- -
67 P3C2R82UGA Y
75 L2D0D32P6X Y
83 NRTTL3ZR0P Y
91 TS7A2RIY5Y Y
99 Q1PDWVU8CH Y
107 JN9YJXAGWE Y
115 VS4972RXU0 Y
123 S7URPXY9AY Y
131 DEK3H4PG6G Y
9 rows selected.
--说明正好对上.
--继续拆分
-- ff 15 01 01 01 01 01 01 01 01 00
-- ff 15 拆开:
-- 11 111 111 , 0001 0101
-- 11 大于192.表示Multi-Byte Groups
-- 111,必须考虑下面的扩展 0x15=21(十进制), 这样6+21=27,表示 27个字节0
-- 下面的111 表示8个字节长度.
--这样拆分下俩就是:
27*8 个0 , 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001
-- 注意后面还有1个00,这个前面讲的单字节组,表示10000000,也就是这个8位的第1位,id就是 64+1-1=64.
-- 实际上这个问题27*8(也就是27*8=216)个0 如何得来的?
SCOTT@test> select header_file,header_block from dba_segments where owner=user and segment_name='T';
HEADER_FILE HEADER_BLOCK
----------- ------------
4 162
4.163 使用 id = 66,131
4,164
4,165
4,166
4.167 使用 id = 1,65
--从rowid开始与结束看,跳过了3个块file#=4,164,165,166块.
--我已经限制每块最大行号65,实际上就是每块最大插入66条记录(行号从0开始).因为位图信息是8位为一组.这样向8位取整,就是72位来表示.
-- 72*3= 216 不是正好表示跳过216个0吗?
===转抄前面的资料:
1.首先前面2位一定是11,只有这样才能大于192.也叫控制位.
2.下面3位表示0字节的数量.
字节数量 0bit的数量
=================================
001 0 0
010 1 8
011 2 16
100 3 24
101 4 32
110 5 40
==================================
其中3位=111,必须扩展到下一字节.
字节数量 0bit的数量
==================================================
111000 00000000 6 48
111000 00000001 7 56
111000 00000010 8 64
....
111000 01111111 133 133*8=1064
111000 10000000 00000001 134 134*8=1072
111000 10000001 00000001 135 135*8=1080
==================================================
. Last three bits indicate number of bytes following control block (minimum 1, maximum 8)
--最后3位是表示位图信息的长度,这里注意000,表示后面占用1个字节. ... 111表示占用8个字节.
===
--下一篇blog将讲解没有Hakan Factor的情况.