前段时间花了点时间研究了一下Oracle压缩表的数据块格式,并给ODU增加了压缩表支持功能。鉴于目前在网络上基本上没有完整的关于Oracle压缩表数据块的格式分析,我觉得有必要把自己的研究得到的知识,发布出来与大家分享。

由于Oracle 9i与Oracle 10g在压缩块格式上没啥区别,我使用ODU也能够在11g上导出压缩表,所以本文就是Windows上的Oracle 9.2.0.8下的压缩表来进行块格式分析。下面我们用DBA_OBJECTS的数据建一个测试表:

SQL> create table t1 as select * from dba_objects;

表已创建。
SQL> select header_file,header_block from dba_segments where owner=user and segment_name='T1';

HEADER_FILE HEADER_BLOCK
----------- ------------
          8          137
SQL> alter system dump datafile 8 block 138;

系统已更改。

由于T1表所在的表空间是MSSM管理方式的表空间,一般来说紧接着段头后面的数据块就是存储表实际数据的第1个块。所以dump出了datafile 8的138块。

下面从块头往下一直进行解析。

Start dump data blocks tsn: 8 file#: 8 minblk 138 maxblk 138
buffer tsn: 8 rdba: 0x0200008a (8/138)
scn: 0x0000.003d0735 seq: 0x02 flg: 0x04 tail: 0x07350602
frmt: 0x02 chkval: 0xe80a type: 0x06=trans data
Block header dump: 0x0200008a
Object id on Block? Y
seg/obj: 0x1be4 csc: 0x00.3d0735 itc: 3 flg: - typ: 1 - DATA
fsl: 0 fnx: 0x0 ver: 0x01

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0xffff.000.00000000  0x00000000.0000.00  C---    0  scn 0x0000.003d0735
0x02   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000
0x03   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000

这一部分是Oracle块的头部,与其他非压缩表块的头部没什么不同。接下来是表类型(相对于索引类型的数据块)的数据头部:

data_block_dump,data header at 0x3393074
===============
tsiz: 0x1f88
hsiz: 0x280
pbl: 0x03393074
bdba: 0x0200008a
     76543210
flag=-0------  这里“O”标记表示是压缩的块
ntab=2     这里说明块里面有两个“表”的数据,实际上是“符号表”和“实际的表数据”,分别是"tab 0"和"tab 1"
nrow=291
frre=-1
fsbo=0x280
fseo=0x28c
avsp=0xc
tosp=0xc
  r0_9ir2=0x0        这里及下面的数行都是压缩表特有的数据
  mec_kdbh9ir2=0x3  这个字段后面有详细说明
  r1_9ir2=0x0
            76543210
  flag_9ir2=------OC
    fcls_9ir2[7]={ 0 32768 32768 32768 32768 32768 32768 }  这个字段后面有详细说明
    perm_9ir2[13]={ 0 11 1 12 6 7 8 9 10 2 3 4 5 }  这个字段后面有详细说明
0x32:pti[0] nrow=122 offs=0
0x36:pti[1] nrow=169 offs=122
0x3a:pri[0] offs=0x189f
0x3c:pri[1] offs=0x1890
0x3e:pri[2] offs=0x1889
0x40:pri[3] offs=0x18ae
0x42:pri[4] offs=0x18c4
0x44:pri[5] offs=0x18ce

行目录数据比较多,在此大部分省略。接下来,就是tab 0,也就是符号表的数据了:

block_row_dump:
tab 0, row 0, @0x189f
tl: 15 fb: --H-FL-- lb: 0x0  cc: 8
col  0: [ 3]  53 59 53
col  1: *NULL*
col  2: [ 5]  56 41 4c 49 44
col  3: [ 1]  4e
col  4: [ 1]  4e
col  5: [ 1]  4e
col  6: *NULL*
col  7: [ 4]  54 59 50 45
bindmp: 00 02 08 76 ff 78 79 79 79 ff cc 54 59 50 45

其实符号表里面,行头部的行标记以及锁标记(即ITL插槽位置)都是固定的,块中没有数据来表示这两项,以节省空间我们主要来看bindmp那一行,那一行数据实际上是该行数据,包括行头部,在块中的原始数据。我们来看看这一行数据各是什么意思:

bindmp: 00 02 08 76 ff 78 79 79 79 ff cc 54 59 50 45
00 02表示的是符号表中这一行被其他地方引用的次数。注意这里是以big endian字节序表示32位整数。
08 表示这一行的列数
76 从这里开始是这一行的实际数据,这是一个“流(Stream)”式数据,基本格式如下:
标志字节 + 数据
标志字节根据不同的值范围,有其不同的含义:
<=200 (0xC8) 表示指向符号表中一行的数据,这个字节是行号。
>200 (0xC8) AND < 250 (0xFA) 表示后面的数据是一列的数据,数据长度为这个字节值减200
=250 (0xFA) 表示后面的数据是一列的数据,只不过数据长度是这个字节后面紧接着的2个字节。注意后面这2个字节表示的长度,是以big endian字节序表示的。
=251 (0xFB) 表示指向符号表中一行的数据,只不过行号是这个字节后面紧接着的2个字节。注意后面这2个字节表示的行号,是以big endian字节序表示的。
=255(0xFF) 表示一个NULL值的列。

回到上面bindmp那一行,76(0x76)小于0xC8,表示引用的是符号表中的一行,行号为118,而118行的数据是53 59 53
tab 0, row 118, @0x1f6c
tl: 6 fb: --H-FL-- lb: 0x0  cc: 1
col  0: [ 3]  53 59 53
bindmp: 00 03 cb 53 59 53
所以这里76就表示序号为0列的数据,数据为53 59 53 从这里可以看出,符号表内部也是会交叉引用的。
接下来:
ff 就表示NULL值,是序号为1的列(注意上面显示的序号是1)
78 79 79 79 这4个字节分别是4次指向符号表中的行的行号。
ff 表示NULL,就是上面显示的序号为6的列,为NULL值。
cc 54 59 50 45 这里0xCC=204大于200,204-200=4。这样后面的4个字节就表示序号为7的列的数据,共4字节长。正如上面显示的序号为7列的数据 54 59 50 45
由于是流式数据,解析到8列就表示这一行数据已经解析完成。

我们再来看看符号表中序号为3的行数据。

tab 0, row 3, @0x18ae
tl: 22 fb: --H-FL-- lb: 0x0  cc: 1
col  0: [19]  32 30 30 39 2d 30 33 2d 31 35 3a 31 37 3a 34 33 3a 31 31
bindmp: 00 02 db 32 30 30 39 2d 30 33 2d 31 35 3a 31 37 3a 34 33 3a 31 31

我们直接看bindmp部分:

00 02 如前面一样表示被引用次数
db 这里就不一样了,在上面的解析中,db本来是表示这一行的列数,但这里显然不是。那么这里表示什么呢?其实这里跳过了列数,因为这一行只有1列。这里就不得不提到,前面块头中:
    mec_kdbh9ir2=0x3
这里mec_kdbh9ir2就表示符号表中有多列的行数,在这之后的行都只有1列。这里值为“3”,那么序号为3的行开始,只有1列,因此省略了此行中列的数目。因此,db就表示此行中唯一的列的长度,0xDB=219,219-200=19,因此db后面的19节字也就是这一列的数据。

符号表相对比较简单一些,在下一篇中我将对实际的数据部分进行解析。

本文解析所用的块dump出来的文件,点击此处下载

,
Trackback

4 comments untill now

  1. […] 接上文《Oracle压缩表数据块格式解析 PartI》,本文将分析压缩表块中实际的行数据部分。 […]

  2. valen wong @ 2010-01-14 15:39

    这盘文章真不错,目前网上解析compress block 最清楚的一篇。
    博主原来是成都的oracle dba啊,看来成都还是有高手啊

    [回复]

    老熊 回复:

    @valen wong, 过奖了

    [回复]

  3. conner2601 @ 2011-09-29 10:42

    [QUOTE]鉴于目前在网络上基本上没有完整的关于Oracle压缩表数据块的格式分析,我觉得有必要把自己的研究得到的知识,发布出来与大家分享。[QUOTE]

    NICE啊,老熊,不止是技术,分享精神真心是非常佩服你。

    [回复]

Add your comment now