yangtingkun
===========================================================
行链接在存储结构上是如何实现的(二)
===========================================================

如果一条记录的长度超过了BLOCK_SIZEOracle会以行链接的形式来存放,不过Oracle到底是如何实现行链接的,一直没有深究,直到有一个网友问起这个问题。

通过例子推断行链接的存储格式。

行链接在存储结构上是如何实现的(一):http://yangtingkun.itpub.net/post/468/465165


上一篇已经提到了问题的关键之处,需要找到Oracle是根据什么确定当前BLOCK中列的数据是否已经完整。

下面继续通过测试来寻找问题的答案:

SQL> create table t1
2 (col1 varchar2(4000),
3 col2 varchar2(4000),
4 col3 varchar2(4000))
5 tablespace test;

表已创建。

SQL> insert into t1 values
2 (lpad('1', 4000, '1'),
3 lpad('2', 3982, '2'),
4 lpad('3', 4000, '3'));

已创建 1 行。

SQL> alter system checkpoint;

系统已更改。

SQL> SELECT DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID), DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) FROM T1;

DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
------------------------------------ ------------------------------------
28 19

SQL> ALTER SYSTEM DUMP DATAFILE 28 BLOCK 19;

系统已更改。

根据前面的例子中,COL2列有18个字节存放在BLOCK1中,而剩余的3982BLOCK存放在第二个BLOCK中。而且根据前面的推测,这个BLOCK的存放似乎是从后向前,也就是说,第二个BLOCK放满后,才开始向第一个BLOCK中写。那么可以构造一个表,使得COL2的长度恰好满足写满第二个BLOCK,这里将长度变为3982,插入记录后,观察dump的结果:

Start dump data blocks tsn: 27 file#: 28 minblk 19 maxblk 19
buffer tsn: 27 rdba: 0x07000013 (28/19)
scn: 0x0001.78a90adb seq: 0x05 flg: 0x04 tail: 0x0adb0605
frmt: 0x02 chkval: 0x105b type: 0x06=trans data
Block header dump: 0x07000013
Object id on Block? Y
seg/obj: 0x98ea csc: 0x01.78a90adb itc: 2 flg: O typ: 1 - DATA
fsl: 0 fnx: 0x0 ver: 0x01

Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x0003.011.00017519 0x00915928.23a1.02 ---- 1 fsc 0x0000.00000000
0x02 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000

data_block_dump,data header at 0xb742d25c
===============
tsiz: 0x1fa0
hsiz: 0x14
pbl: 0xb742d25c
bdba: 0x07000013
76543210
flag=--------
ntab=1
nrow=1
frre=-1
fsbo=0x14
fseo=0xff4
avsp=0xfe0
tosp=0xfe0
0xe:pti[0] nrow=1 offs=0
0x12:pri[0] offs=0xff4
block_row_dump:
tab 0, row 0, @0xff4
tl: 4012 fb: --H-F--- lb: 0x1 cc: 1
nrid: 0x07000012.0
col 0: [4000]
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 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 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 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31
end_of_block_dump
End dump data blocks tsn: 27 file#: 28 minblk 19 maxblk 19

可以看到BLOCK1中只存放了COL1,而没有COL2的任何信息,这进一步说明这里先写的是BLOCK2,而后写的BLOCK1

SQL> ALTER SYSTEM DUMP DATAFILE 28 BLOCK 18;

系统已更改。

根据DUMP结果中的行链接ROWID,继续DUMP行链接BLOCK2的信息:

Start dump data blocks tsn: 27 file#: 28 minblk 18 maxblk 18
buffer tsn: 27 rdba: 0x07000012 (28/18)
scn: 0x0001.78a90adb seq: 0x06 flg: 0x04 tail: 0x0adb0606
frmt: 0x02 chkval: 0xbcbf type: 0x06=trans data
Block header dump: 0x07000012
Object id on Block? Y
seg/obj: 0x98ea csc: 0x01.78a90adb itc: 3 flg: - typ: 1 - DATA
fsl: 0 fnx: 0x0 ver: 0x01

Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x0003.011.00017519 0x00915928.23a1.01 ---- 1 fsc 0x0000.00000000
0x02 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
0x03 0x0000.000.00000000 0x00000000.0000.00 C--- 0 scn 0x0000.00000000

data_block_dump,data header at 0xb742d274
===============
tsiz: 0x1f88
hsiz: 0x14
pbl: 0xb742d274
bdba: 0x07000012
76543210
flag=--------
ntab=1
nrow=1
frre=-1
fsbo=0x14
fseo=0x51
avsp=0x3d
tosp=0x3d
0xe:pti[0] nrow=1 offs=0
0x12:pri[0] offs=0x51
block_row_dump:
tab 0, row 0, @0x51
tl: 7991 fb: -----L-- lb: 0x1 cc: 2
col 0: [3982]
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 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 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 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: [4000]
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 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 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 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33
end_of_block_dump
End dump data blocks tsn: 27 file#: 28 minblk 18 maxblk 18

其实根据Oracle分配BLOCK的顺序也可以看出Oracle先分配的BLOCK2,写满之后,分配BLOCK1,在BLOCK1中留下一个BLOCK2的地址信息。

下面就是要寻找记录列信息的标识了,通过对比上面几个DUMP的结果,首先怀疑的是cc的值,这个例子中,BLOCK1cc的值是1,说明这个BLOCK列的最后一列是第一列,而BLOCK2cc的值是2,说明BLOCK的开头列为2。那么是否假设一致呢,下面在做一个例子进行测试:

SQL> create table t2
2 (col1 varchar2(1000),
3 col2 varchar2(1000),
4 col3 varchar2(1000),
5 col4 varchar2(1000),
6 col5 varchar2(4000),
7 col6 varchar2(4000))
8 tablespace test;

表已创建。

SQL> insert into t2 values
2 (lpad('1', 1000, '1'),
3 lpad('2', 1000, '2'),
4 lpad('3', 1000, '3'),
5 lpad('4', 1000, '4'),
6 lpad('5', 4000, '5'),
7 lpad('6', 4000, '6'));

已创建 1 行。

SQL> commit;

提交完成。

SQL> alter system checkpoint;

系统已更改。

SQL> SELECT DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID), DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) FROM T2;

DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
------------------------------------ ------------------------------------
28 27

SQL> ALTER SYSTEM DUMP DATAFILE 28 BLOCK 27;

系统已更改。

SQL> ALTER SYSTEM DUMP DATAFILE 28 BLOCK 26;

系统已更改。

观测DUMPtrace文件:

Start dump data blocks tsn: 27 file#: 28 minblk 27 maxblk 27
buffer tsn: 27 rdba: 0x0700001b (28/27)
scn: 0x0001.79f5e324 seq: 0x01 flg: 0x06 tail: 0xe3240601
frmt: 0x02 chkval: 0x5a86 type: 0x06=trans data
Block header dump: 0x0700001b
Object id on Block? Y
seg/obj: 0x98eb csc: 0x01.79f5e321 itc: 2 flg: O typ: 1 - DATA
fsl: 0 fnx: 0x0 ver: 0x01

Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x0009.001.00016d53 0x00910f26.075b.1f --U- 1 fsc 0x0000.79f5e324
0x02 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000

data_block_dump,data header at 0xb742d25c
===============
tsiz: 0x1fa0
hsiz: 0x14
pbl: 0xb742d25c
bdba: 0x0700001b
76543210
flag=--------
ntab=1
nrow=1
frre=-1
fsbo=0x14
fseo=0xfd8
avsp=0xfc4
tosp=0xfc4
0xe:pti[0] nrow=1 offs=0
0x12:pri[0] offs=0xfd8
block_row_dump:
tab 0, row 0, @0xfd8
tl: 4040 fb: --H-F--N lb: 0x1 cc: 5
nrid: 0x0700001a.0
col 0: [1000]
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 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 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31
col 1: [1000]
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 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 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32
col 2: [1000]
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 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 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33
col 3: [1000]
34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34
34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34
.
.
.
34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34
col 4: [18] 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35
end_of_block_dump
End dump data blocks tsn: 27 file#: 28 minblk 27 maxblk 27
*** 2008-04-18 16:56:50.892
Start dump data blocks tsn: 27 file#: 28 minblk 26 maxblk 26
buffer tsn: 27 rdba: 0x0700001a (28/26)
scn: 0x0001.79f5e324 seq: 0x01 flg: 0x06 tail: 0xe3240601
frmt: 0x02 chkval: 0x9e47 type: 0x06=trans data
Block header dump: 0x0700001a
Object id on Block? Y
seg/obj: 0x98eb csc: 0x01.79f5e321 itc: 3 flg: - typ: 1 - DATA
fsl: 0 fnx: 0x0 ver: 0x01

Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x0009.001.00016d53 0x00910f26.075b.1e --U- 1 fsc 0x0000.79f5e324
0x02 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
0x03 0x0000.000.00000000 0x00000000.0000.00 C--- 0 scn 0x0000.00000000

data_block_dump,data header at 0xb742d274
===============
tsiz: 0x1f88
hsiz: 0x14
pbl: 0xb742d274
bdba: 0x0700001a
76543210
flag=--------
ntab=1
nrow=1
frre=-1
fsbo=0x14
fseo=0x51
avsp=0x3d
tosp=0x3d
0xe:pti[0] nrow=1 offs=0
0x12:pri[0] offs=0x51
block_row_dump:
tab 0, row 0, @0x51
tl: 7991 fb: -----LP- lb: 0x1 cc: 2
col 0: [3982]
35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35
35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35
.
.
.
35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35
35 35 35 35 35 35 35
col 1: [4000]
36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36
36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36
36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36
.
.
.
36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36
end_of_block_dump
End dump data blocks tsn: 27 file#: 28 minblk 26 maxblk 26

从上面的红色cc信息不难看出,cc代表的值并不是上面推测的当前块中列的起始值。其实根据这个不难推测,这个cc的值,实际上是当前数据库块中列的个数。(推测CCCOLUMN COUNT的缩写)

找到了一个和列相关的信息,不过这个信息仍然不能解决问题,因为第一个篇文章中提出的例子,仅通过列的个数,仍然不能解决。也就是说,还有其他的标识位存在来表示行链接的存储信息。

yangtingkun 发表于:2008.06.30 21:44 ::分类: ( ORACLE ) ::阅读:(522次) :: 评论 (0)

发表评论
标题

在此添加评论
表情符号: smile laughing tongue angry crying sad wassat wink

称呼

邮箱地址(可选)

个人主页(可选)

 authimage


切换风格
新闻聚合
博客日历
文章归档...
最新发表...
最新评论...
最多阅读文章...
最多评论文章...
博客统计...
Blog信息
网站链接...