[20141008]索引字符串的长度问题.txt
--oracle 的B tree 索引,一般保存方式是长度+键值+...+长度+rowid键值,如果索引唯一,rowid在前面(没有长度指示器),这样可以节省1个字节.
--但是如果索引的字符串长度长度比如超过255个字符,这样索引的长度部分如何保存呢?
--曾经写过一篇"varchar2(4000)如何保存",链接如下:
http://blog.itpub.net/267265/viewspace-747304/
如果一行能被存储于一个数据块(data block)中,那么其行头(row header)所需容量将不少于 3 字节(byte)。在行头信息之后依次
储存的是各列的列长(column length)及列值(column value)。列长存储于列值之前,如列值不超过250 字节,那么 Oracle使用1字节存
储其列长;如列值超过 250 字节,则使用 3 字节存储其列长。列数据(column data)所需的存储空间取决于此列的数据类型(datatype)。
如果某列的数据类型为变长(variable length)的,那么存储此列值所需的空间可能会随着数据更新而增长或缩小。
总结:
1.如果列值长度小于等于250字节,Oracle使用1字节存储其列长.内容为字段的长度.
2.如果列值长度超过250字节,则使用3字节存储其列长。前面1个字节使用0xfe(表示超过250),后面2个字节表示列值长度.
--所以,我开始想这个应该跟字符串在数据块的保存方式一致,实际情况呢?做一个测试看看:
1.建立测试环境:
SCOTT@test> @ver
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
create table t ( a varchar2(200),b varchar2(3000));
insert into t values (lpad('1',127,'1'),lpad('a',127,'a'));
insert into t values (lpad('2',127,'2'),lpad('b',128,'b'));
insert into t values (lpad('3',127,'3'),lpad('c',1000,'c'));
commit;
create index i_t_a_b on t(a,b);
exec dbms_stats.gather_table_stats(ownname=>user, tabname=>'t', estimate_percent=>null, method_opt=>'FOR ALL COLUMNS SIZE 1');
2.转储索引信息:
SCOTT@test> select segment_name,header_file,header_block from dba_segments where owner=user and segment_name='I_T_A_B';
SEGMENT_NAME HEADER_FILE HEADER_BLOCK
-------------------- ----------- ------------
I_T_A_B 4 562
--4*127+128+1000=1636,可以估计应该都保存在索引的root节点.为EADER_BLOCK+1.
alter system checkpoint ;
alter system dump datafile 4 block 563 ;
Leaf block dump
===============
header address 182927614564=0x2a9755e264
kdxcolev 0
KDXCOLEV Flags = - - -
kdxcolok 0
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 3
kdxcosdc 0
kdxconro 3
kdxcofbo 42=0x2a
kdxcofeo 6361=0x18d9
kdxcoavs 6319
kdxlespl 0
kdxlende 0
kdxlenxt 0=0x0
kdxleprv 0=0x0
kdxledsz 0
kdxlebksz 8032
row#0[7767] flag: ------, lock: 0, len=265
col 0; len 127; (127):
31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31
...
31 31
col 1; len 127; (127):
61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
...
61 61
col 2; len 6; (6): 01 00 02 13 00 00
row#1[7500] flag: ------, lock: 0, len=267
col 0; len 127; (127):
32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32
...
32 32
col 1; len 128; (128):
62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62
...
62 62 62
col 2; len 6; (6): 01 00 02 13 00 01
row#2[6361] flag: ------, lock: 0, len=1139
col 0; len 127; (127):
33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33
...
33 33
col 1; len 1000; (1000):
63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63
....
63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63
col 2; len 6; (6): 01 00 02 13 00 02
----- end of leaf block dump -----
End dump data blocks tsn: 4 file#: 4 minblk 563 maxblk 563
--可以发现第一条索引条目前面的flag,lock占用2个字节 1+127+1+127+1+6=263, 2+263=265,正好符合.
--但是第二条索引条目,仅仅b字段增加1个字节,应该总厂266才对,而实际上是267.why?
SCOTT@test> @10to16 1000
10 to 16 HEX REVERSE16
-------------- ------------------
00000000003e8 0xe8030000
--从转储内容看:
Dump of memory from 0x0000002A9755E200 to 0x0000002A97560200
2A9755E200 0000A206 01000233 B7C4186D 04010002 [....3...m.......]
2A9755E210 0000C7B6 00046F02 0004735E B7C4186B [.....o..^s..k...]
2A9755E220 00000002 00320002 01000230 00000000 [......2.0.......]
2A9755E230 00000000 00000000 00000000 00000000 [................]
2A9755E240 00000000 0000FFFF 00000000 00000000 [................]
2A9755E250 00000000 00028000 B7C4186B 00000000 [........k.......]
2A9755E260 00000000 03800000 00000000 002A0003 [..............*.]
2A9755E270 18AF18D9 00000000 00000000 00000000 [................]
2A9755E280 00000000 00001F60 1D4C1E57 AAAA18D9 [....`...W.L.....]
2A9755E290 AAAAAAAA AAAAAAAA AAAAAAAA AAAAAAAA [................]
Repeat 118 times
2A9755EA00 AAAAAAAA AAAAAAAA 00000000 00000000 [................]
2A9755EA10 00000000 00000000 00000000 00000000 [................]
Repeat 273 times
2A9755FB30 00000000 00000000 00000000 7F000000 [................]
2A9755FB40 33333333 33333333 33333333 33333333 [3333333333333333]
Repeat 6 times
2A9755FBB0 33333333 33333333 33333333 83333333 [333333333333333.]
2A9755FBC0 636363E8 63636363 63636363 63636363 [.ccccccccccccccc] 2A9755FBD0 63636363 63636363 63636363 63636363 [cccccccccccccccc]
Repeat 60 times
2A9755FFA0 63636363 63636363 00010663 02001302 [ccccccccc.......]
2A9755FFB0 327F0000 32323232 32323232 32323232 [...2222222222222]
2A9755FFC0 32323232 32323232 32323232 32323232 [2222222222222222]
Repeat 6 times
2A97560030 80803232 62626262 62626262 62626262 [22..bbbbbbbbbbbb] 2A97560040 62626262 62626262 62626262 62626262 [bbbbbbbbbbbbbbbb]
Repeat 6 times
2A975600B0 62626262 02000106 00010013 31317F00 [bbbb..........11]
2A975600C0 31313131 31313131 31313131 31313131 [1111111111111111]
Repeat 6 times
2A97560130 31313131 31313131 31313131 61617F31 [1111111111111.aa] 2A97560140 61616161 61616161 61616161 61616161 [aaaaaaaaaaaaaaaa]
Repeat 6 times
2A975601B0 61616161 61616161 61616161 00010661 [aaaaaaaaaaaaa...]
2A975601C0 00001302 00000000 00000000 00000000 [................]
2A975601D0 00000000 00000000 00000000 00000000 [................]
Repeat 1 times
2A975601F0 00000000 00000000 00000000 186D0601 [..............m.]
对比转储,可以猜测与总结如下:
1.当字符串长度小于等于127时,使用1个字节表示长度.
2.当字符串大于等于128时,使用2个字节来保存长度,内容为字符串长度+0x8000.
3.真搞不懂为什么与数据块的保存方式不同,oracle要创造2种不同的方式保存字符串.
--补充通过bbed观察看看.
BBED> set dba 4,563
DBA 0x01000233 (16777779 4,563)
BBED> p kd_off
sb2 kd_off[0] @132 8032
sb2 kd_off[1] @134 0
sb2 kd_off[2] @136 7767
--kd_off[1] 指向 0,难道中间靠前面的信息来推断吗? 这个东西不是很理解,先放一下.
BBED> p *kd_off[2]
rowdata[1410]
-------------
ub1 rowdata[1410] @7867 0x00
BBED> x /rccx
rowdata[1410] @7867
-------------
flag@7867: 0x00 (NONE)
lock@7868: 0x00
data key:
col 0[127] @7870: 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
col 1[127] @7998: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
col 2[6] @8126: 0x01 0x00 0x02 0x13 0x00 0x00
BBED> dump /v offset 7997 count 32
File: /u01/app/oracle11g/oradata/test/users01.dbf (4)
Block: 563 Offsets: 7997 to 8028 Dba:0x01000233
---------------------------------------------------------------------------------------------------------------------------------------------------------------
7f616161 61616161 61616161 61616161 61616161 61616161 61616161 61616161 l .aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-- 0x7f=127.
BBED> set offset 7600
OFFSET 7600
BBED> x /rccx
rowdata[1143] @7600
-------------
flag@7600: 0x00 (NONE)
lock@7601: 0x00
data key:
col 0[127] @7603: 2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
col 1[128] @7732: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
col 2[6] @7861: 0x01 0x00 0x02 0x13 0x00 0x01
BBED> dump /v offset 7730 count 32
File: /u01/app/oracle11g/oradata/test/users01.dbf (4)
Block: 563 Offsets: 7730 to 7761 Dba:0x01000233
---------------------------------------------------------------------------------------------------------------------------------------------------------------
80806262 62626262 62626262 62626262 62626262 62626262 62626262 62626262 l ..bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
--8080表示长度128.
BBED> set offset 6461
OFFSET 6461
BBED> x /rccx
rowdata[4] @6461
----------
flag@6461: 0x00 (NONE)
lock@6462: 0x00
data key:
col 0[127] @6464: 3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333
col 1[1000] @6593: ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
...
cccc
col 2[6] @7594: 0x01 0x00 0x02 0x13 0x00 0x02
BBED> dump /v offset 6591 count 32
File: /u01/app/oracle11g/oradata/test/users01.dbf (4)
Block: 563 Offsets: 6591 to 6622 Dba:0x01000233
---------------------------------------------------------------------------------------------------------------------------------------------------------------
83e86363 63636363 63636363 63636363 63636363 63636363 63636363 63636363 l ..cccccccccccccccccccccccccccccc
--83e8 表示长度1000.