Block Row Chaining

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

http://yangtingkun.itpub.net/post/468/465165

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

如果知道答案,这个问题并不困难,所以如果只是将结果贴出来可能意义并不大,因此这里将寻找答案的整个探索过程贴出来,希望能起到抛砖引玉的作用。

首先将问题描述的清晰一些,如果表中的某一条记录的长度超过了DB_BLOCK_SIZE的大小,则Oracle没有办法在一个BLOCK中存放这条记录。显然这条记录会存放到多个BLOCK中,而且出于空间利用的考虑,Oracle在将记录存放到多个BLOCK的时候,并不会保证每列都完整的放在一个BLOCK上,因为VARCHAR2(4000)列或LONG列本身可能会大于1个BLOCK的大小。

可以推断,Oracle尽可能在每个BLOCK中写满数据,写不下的数据会写到另外的BLOCK中:

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

表已创建。

SQL> insert into t values
2 (lpad('1', 4000, '1'),
3 lpad('2', 4000, '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 T;

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

SQL> ALTER SYSTEM DUMP DATAFILE 28 BLOCK 11;

系统已更改。

下面看看对应的DUMP文件信息:

buffer tsn: 27 rdba: 0x0700000b (28/11)
scn: 0x0001.78a8fb01 seq: 0x05 flg: 0x04 tail: 0xfb010605
frmt: 0x02 chkval: 0xccd4 type: 0x06=trans data
Block header dump: 0x0700000b
Object id on Block? Y
seg/obj: 0x98e9 csc: 0x01.78a8fb01 itc: 2 flg: O typ: 1 - DATA
fsl: 0 fnx: 0x0 ver: 0x01

Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x0003.010.00017778 0x00915927.23a1.48 ---- 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: 0x0700000b
76543210
flag=--------
ntab=1
nrow=1
frre=-1
fsbo=0x14
fseo=0xfe1
avsp=0xfcd
tosp=0xfcd
0xe:pti[0] nrow=1 offs=0
0x12:pri[0] offs=0xfe1
block_row_dump:
tab 0, row 0, @0xfe1
tl: 4031 fb: --H-F--N lb: 0x1 cc: 2nrid: 0x0700000a.0col 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
.
.
.
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: [18] 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32
end_of_block_dump
End dump data blocks tsn: 27 file#: 28 minblk 11 maxblk 11

可以看到,这个BLOCK并没有在整列的时候中断,而是在这个块中写了部分COL2的数据。这就证实文章开头的推测。

从上面红色的地址可以找到下一个BLOCK:

SQL> select dump(rowid, 16) from t;

DUMP(ROWID,16)


Typ=69 Len=10: 0,0,98,e9,7,0,0,b,0,0

SQL> ALTER SYSTEM DUMP DATAFILE 28 BLOCK 10;

系统已更改。

无论是和当前记录的ROWID对比,还是根据ROWID的存储格式特点,都可以确定下一个BLOCK的位置,对这个BLOCK进行DUMP,再次观察:

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

Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x0003.010.00017778 0x00915927.23a1.47 ---- 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: 0x0700000a
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]
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 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 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
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
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 10 maxblk 10

看完这个BLOCK的结果,可以发现Oracle似乎是从后向前进行的写操作,之所以这样说是因为这个块被写满了,而前一块并没有被写满。

根据两个BLOCK结构的分析,基本上确认了文章开始的分析,也就是Oracle一个块无法写下全部记录的时候,会通过行链接实现,而实现的方式就是在块头处通过ROWID的方式之处下一个存放记录的块的位置。

虽然这个问题解决了,但是还存在一个新的问题。前面提到了,Oracle并不是以列作为划分记录的单位,一列的数据可能分布到多个BLOCK上,比如这个例子。那么Oracle是如何确定当前BLOCK存放最后一列记录是否完整呢。

每个BLOCK中,数据存放都是从COL0开始排序递增的,因此这个COL的编号是块内的编号,而不是记录内的列的编号,显然无法通过这个COL位置来确定列的信息。

虽然这个例子本身没有疑问,因为表本身包含3个列,而每个BLOCK都有两个列,显然是第二个列在第一个BLOCK中没有完全存储,部分内容写到了第二个BLOCK中。但是这种分析并不适用所有的情况,假设当前表就是4个字段,那么根据DUMP的结果就没有办法判断是COL2被分散到了两个BLOCK,且COL4为空;还是COL2的长度就是18,而COL3的长度是3982,COL4长度是4000。

因此,Oracle肯定通过其他的手段记录了这个信息。

yangtingkun 发表于:2008.06.28 23:51 ::分类: ( ORACLE ) ::阅读:(1459次) :: 评论 (4)
re: 行链接在存储结构上是如何实现的(一) [回复]
从哪里看到的下一个数据块是10啊,谢谢

mengxb 评论于: 2008.12.16 19:18
re: 行链接在存储结构上是如何实现的(一) [回复]
HTML中没有显示出红色标识。
标识行链接的地址信息是:nrid: 0x0700000a

yangtingkun 评论于: 2008.12.17 19:12
re: 行链接在存储结构上是如何实现的(一) [回复]
能问一下 select dump(rowid, 16) from t; 这个是怎么来的吗?

jlcchu 评论于: 2008.12.22 17:19
re: 行链接在存储结构上是如何实现的(一) [回复]
dump(rowid, 16)是指16进制显示。

yangtingkun 评论于: 2008.12.24 09:31

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

http://yangtingkun.itpub.net/post/468/465376

如果一条记录的长度超过了BLOCK_SIZE,Oracle会以行链接的形式来存放,不过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中,而剩余的3982个BLOCK存放在第二个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的值,这个例子中,BLOCK1中cc的值是1,说明这个BLOCK列的最后一列是第一列,而BLOCK2中cc的值是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;

系统已更改。

观测DUMP的trace文件:

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的值,实际上是当前数据库块中列的个数。(推测CC是COLUMN COUNT的缩写)

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

yangtingkun 发表于:2008.06.30 21:44 ::分类: ( ORACLE ) ::阅读:(1217次) :: 评论 (4)
re: 行链接在存储结构上是如何实现的(二) [回复]
您好想请教一下,为什么我dump出的结果只有Col 0的信息?在10gR2,11gR1分别测试了都是这个结果,具体如下

Start dump data blocks tsn: 6 file#:5 minblk 7212 maxblk 7212
Block dump from cache:
Dump of buffer cache at level 4 for tsn=6, rdba=20978732
BH (0x3A3FD16C) file#: 5 rdba: 0x01401c2c (5/7212) class: 1 ba: 0x3A3DC000
set: 3 bsz: 8192 bsi: 0 sflg: 2 pwc: 1245 lid: 0x00000000,0x00000000
dbwrid: 0 obj: 71343 objn: 71343 tsn: 6 afn: 5
hash: [0x54D56220,0x54D56220] lru: [0x3A3FD29C,0x3A3FD0FC]
ckptq: [NULL] fileq: [NULL] objq: [0x3A7E426C,0x3A3FD15C]
st: XCURRENT md: NULL tch: 1
flags: block_written_once redo_since_read gotten_in_current_mode
LRBA: [0x0.0.0] LSCN: [0x0.0] HSCN: [0xffff.ffffffff] HSUB: [1]
cr pin refcnt: 0 sh pin refcnt: 0
buffer tsn: 6 rdba: 0x01401c2c (5/7212)
scn: 0x0000.003c310f seq: 0x01 flg: 0x06 tail: 0x310f0601
frmt: 0x02 chkval: 0x8117 type: 0x06=trans data
Hex dump of block: st=0, typ_found=1
Dump of memory from 0x3A3DC000 to 0x3A3DE000
3A3DC000 0000A206 01401C2C 003C310F 06010000 [....,.@..1

xxd 评论于: 2010.05.26 15:46
 re: 行链接在存储结构上是如何实现的(二) [回复]
上边没贴全,把最后一部分补充了
tl: 1012 fb: --H-F--- lb: 0x1 cc: 1
nrid: 0x01401c30.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
end_of_block_dump
End dump data blocks tsn: 6 file#: 5 minblk 7212 maxblk 7212

xxd 评论于: 2010.05.26 15:47
re: 行链接在存储结构上是如何实现的(二) [回复]
应该和你的块大小有关,你现在看到的是头块,其余部分存在其他的block中,根据上面给出的链接地址,继续dump其他的数据块:
nrid: 0x01401c30

yangtingkun 评论于: 2010.05.26 20:13
re: 行链接在存储结构上是如何实现的(二) [回复]
谢谢您的回复,根据这个nrid找到了下一个数据块7216,继续dump就得到了我要的结果,那么反向推理出这个extent是从7209开始分配的一直到7217,共8个数据块.其中3个数据块有数据,其他的dump不出,那么就是空块了.

xxd 评论于: 2010.05.27 11:11