http://czmmiao.iteye.com/blog/1495332
最近在研究块的内部结构,把文档简单整理了一下,和大家分享一下。该篇文章借助dump和BBED对数据
库内部结构进行了分析,最后附加了一个用BBED解决ORA-1200错误的小例子。在总结的过程中参考了
《Disassembling the Oracle Data Block》以及网上的翻译版本。
dump说明
创建表空间和测试表:
create tablespace testblock datafile '/opt/oracle/oradata/oradb/testblock01.dbf' size 100M;
create table testblock(
id number,
name varchar(4)
) tablespace testblock;
插入3条数据然后提交:
SQL>
SQL>
SQL>
SQL>
SQL> select * from testblock;
---------- --------
SQL> select rowid,dbms_rowid.rowid_relative_fno(rowid) rel_fno,dbms_rowid.rowid_block_number(rowid)
blockno from testblock;
ROWID
------------------
AAANK4AAFAAAAAQAAA
AAANK4AAFAAAAAQAAB
AAANK4AAFAAAAAQAAC
我们看到这3行数据都在5号数据文件的第16个块
执行数据块dump:
SQL> alter system dump datafile 5 block 16;
以下是该数据块的完整dump结果:
Start dump data blocks tsn: 7 file#: 5 minblk 16 maxblk 16
buffer tsn: 7 rdba: 0x01400010 (5/16)
scn: 0x0000.001732d3 seq: 0x01 flg: 0x04 tail: 0x32d30601
frmt: 0x02 chkval: 0x84cb type: 0x06=trans data
Hex dump of block: st=0, typ_found=1
Dump of memory from 0x0CEB6400 to 0x0CEB8400
CEB6400 0000A206 01400010 001732D3 04010000
CEB6410 000084CB 00000001 0000D2B8 001732D3
CEB6420 00000000 00320002 01400009 00200006
CEB6430 00000271 00800205 00130257 00008000
CEB6440 001732C4 00060008 00000279 00800351
CEB6450 00150278 00000001 00000000 00000000
CEB6460 00000000 00030100 0018FFFF 1F651F5E
CEB6470 00001F65 1F5E0003 1F801F66 00000000
CEB6480 00000000 00000000 00000000 00000000
CEB83C0 022C0000 02C10202 002C6101 03C10202
CEB83D0 012C6201 03C10202 2C626202 C1020200
CEB83E0 61610202 0202002C 630104C1 0202002C
CEB83F0 620103C1 0202002C 610102C1 32D30601
Block header dump:
0x01
0x02
data_block_dump,data header at 0xceb6464
===============
tsiz: 0x1f98
hsiz: 0x18
pbl: 0x0ceb6464
bdba: 0x01400010
flag=--------
ntab=1
nrow=3
frre=-1
fsbo=0x18
fseo=0x1f5e
avsp=0x1f65
tosp=0x1f65
0xe:pti[0]
0x12:pri[0]
0x14:pri[1]
0x16:pri[2]
block_row_dump:
tab 0, row 0, @0x1f5e
tl: 8 fb: --H-FL-- lb: 0x2
col
col
tab 0, row 1, @0x1f66
tl: 8 fb: --H-FL-- lb: 0x0
col
col
tab 0, row 2, @0x1f80
tl: 8 fb: --H-FL-- lb: 0x0
col
col
end_of_block_dump
End dump data blocks tsn: 7 file#: 5 minblk 16 maxblk 16
头信息区
这个区包括数据块的地址,数据块类型,检查点信息,scn信息等信息。
---------
Start dump data blocks tsn: 7 file#: 5 minblk 16 maxblk 16
buffer tsn: 7 rdba: 0x01400010 (5/16)
scn: 0x0000.001732d3 seq: 0x01 flg: 0x04 tail: 0x32d30601
frmt: 0x02 chkval: 0x84cb type: 0x06=trans data
---------
buffer tsn:7
rdba: 0x01400010 (5/16)
我们看到前10位转换成十进制就是5,后22位转换成十进制就是16。rdba在数据块中的offset是4,即rdba存在于数据块中的第5-9字节中(offset从0开始算),数据块中的每个部分在数据块中的偏移量后边会通过BBED展
示,这里可以先不关心。
scn: 0x0000.001732d3
Base。如果SCN Base达到了4个字节表示的最大值,SCN Wrap+1,SCN Base清0。在数据块中的offset是8
seq: 0x01
flg: 0x04
tail: 0x32d30601
SCN Base的低2个字节+type+seq。即tail: 0x32d30601=32d3+06+01
frmt: 0x02
chkval: 0x84cb
type: 0x06=trans data
Header Block Types
ID
01
02
03
04
05
06
07
08
09
10
11
数据区、空闲区
数据区是真正存储数据的地方
Dump of memory from 0x0CEB6400 to 0x0CEB8400
CEB6400 0000A206 01400010 001732D3 04010000
CEB6410 000084CB 00000001 0000D2B8 001732D3
CEB6420 00000000 00320002 01400009 00200006
CEB6430 00000271 00800205 00130257 00008000
CEB6440 001732C4 00060008 00000279 00800351
CEB6450 00150278 00000001 00000000 00000000
CEB6460 00000000 00030100 0018FFFF 1F651F5E
CEB6470 00001F65 1F5E0003 1F801F66 00000000
CEB6480 00000000 00000000 00000000 00000000
CEB83C0 022C0000 02C10202 002C6101 03C10202
CEB83D0 012C6201 03C10202 2C626202 C1020200
CEB83E0 61610202 0202002C 630104C1 0202002C
CEB83F0 620103C1 0202002C 610102C1 32D30601
事物列表区
事务列表区包括了在这个数据块内的事务,也就是我们知道的ITL(interested transaction list),从中我们可以知道XID(transaction id),UBA(undo block address)等信息。
事物列表区分析:
--------------
Block header dump:
0x01
0x02
---------------
seg/obj: 0xd2b8
SQL> select to_number('d2b8','xxxxxx') from dual;
TO_NUMBER('D2B8','XXXXXX')
------------------------------
SQL> select object_name,object_type from dba_objects where object_id=53944;
OBJECT_NAME
------------------------------ --------------------
TESTBLOCK
csc: 0x00.1732d3
itc: 2
flg: E
typ: 1 - DATA
bdba
下边我们重点看一下ITL事物槽。Oracle的每个数据块中都有一个或者多个事务槽,每一个对数据块的并发访问
事务都会占用一个事务槽。
每个事物都会ITL事物槽由槽位号、XID、Uba、Flag、Lck、Scn/Fsc几部分组成。
0x01
0x02
Xid:事务id,在回滚段事务表中有一条记录和这个事务对应。Xid组成:Undo Segment Number +Transaction
Table Slot Number+ Wrap
Uba:回滚段地址,该事务对应的回滚段地址。Uba组成:回滚块地址(undo文件号和数据块号)+回滚序列号+
回滚记录号
SQL> select xidusn,xidslot,xidsqn,ubafil,ubablk,ubasqn,ubarec from v$transaction;
Flag:事务标志位。这个标志位就记录了这个事务的操作状态,各个标志的含义分别是:
C = transaction has been committed and locks cleaned out
B = this undo record contains the undo for this ITL entry
U = transaction committed (maybe long ago); SCN is an upper bound
T
上如果有已经提交的事务,那么在clean ount的时候,块会被进行清除,但是这个块里面的事务不会被清除。
Lck:表示这个事务所影响的行数。我们看到01号事物槽Lck为0,因为该事物槽中的事物Flag为C,证明该事物
已经提交,锁也被清楚掉了,该事物槽可以被重用了。02号事物槽Lck为1,是因为我对第一行做了一个更新,
并且没有提交,Flag为----说明该事物是活动的。
Scn/Fsc:Commit SCN或者快速提交(Fast Commit Fsc)的SCN。
每条记录中的行级锁对应Itl条目lb,对应于Itl列表中的序号,即那个事务在该记录上产生的锁。
对于Oracle来说,对于一个事务,可以是快速提交、也可以是延迟提交,目的都是为了提高提交的速度。提交以后,oracle需要对ITL事务槽、每一行的锁定标记进行清除。如果是快速提交,那么在提交的时候,会将事务表和每一个数据块的ITL槽进行清除。但是锁定标记可能没有清除,等下次用到的时候再进行清除。如果是延迟提交,那么在提交的时候,只是将事务表进行清除,并没有对ITL事务槽进行清除,每一行的锁定标记也没有清除。因此C和U的情况特别多。块清除的过程并不包括每个行的锁定标记的清除,主要指的是ITL的清除。
注意:
1、事务槽中首先记录的是Xid和Uba,只有在提交以后,当对这个数据块进行cleanout的时候,才会更新Flag和Scn。因此Oracle总是以事务表中对这个数据块的Scn以及Flag为准。
2、一个事务开始以后,在一个数据块上得到一个事务槽,那么在这个事务提交以前,这个事务槽会一直占用,直到这个事务提交释放这个事务槽。
3、只有在已经提交以后,这个itl事务槽中的scn才会有数值。
4、事务是否已经提交、事务对应的SCN,这些信息都是以回滚段事务表中的为主,事务槽中的不准确
5、事务槽中的事务id和uba地址是准确的
6、事务槽1中的事务id和回滚段中的事务id肯定不是一样的,不同回滚段中的事务id也一定不一样。
尾区
尾区储存着数据块的描述信息
data_block_dump,data header at 0xceb6464
===============
tsiz: 0x1f98
hsiz: 0x18
pbl: 0x0ceb6464
bdba: 0x01400010
flag=--------
ntab=1
nrow=3
frre=-1
fsbo=0x18
fseo=0x1f5e
avsp=0x1f65
tosp=0x1f65
0xe:pti[0]
0x12:pri[0]
0x14:pri[1]
0x16:pri[2]
tab 0, row 0, @0x1f5e
tl: 8 fb: --H-FL-- lb: 0x2
col
col
tab 0, row 1, @0x1f66
tl: 8 fb: --H-FL-- lb: 0x0
col
tab 0, row 2, @0x1f80
tl: 8 fb: --H-FL-- lb: 0x0
col
col
―――――――――――――
tl
fb
N- Last column cintinues in next piece
当我们delete一行数据的时候,数据并不是物理的被删除,而是把该行标记为删除,这个时候fb应该是--HDFL-- 而不是原来的--H-FL-- 。把第3行数据删除后提交,重新dump一下:
tab 0, row 2, @0x1f80
tl: 8 fb: --HDFL-- lb: 0x0
col
col
Lb
Cc
col
col
SQL> select dump(1,16) from dual;
DUMP(1,16)
-----------------
Typ=2 Len=2: c1,2
SQL> select dump('a',16) from dual;
DUMP('A',16)
----------------
Typ=96 Len=1: 61
参考至:http://wenku.baidu.com/view/ebfcad85d4d8d15abf234e06
如有错误,欢迎指正
邮箱:czmcj@163.com