众所周知,Oracle的数据是储存在数据文件中的。那么Oracle是以什么格式来储存数据的呢?相信大家都对其内部结构很感兴趣。这篇文章就帮大家来了解Oracle数据文件的内部结构。
我们知道数据库储存的最小单位是数据块,其他如extent,segment,tablespace等都是由数据块组成,所以我们就从数据块的结构来分析。
典型的数据块由3部分构成:
1. 头信息区 这个区包括数据块的地址,数据块类型,检查点信息,scn信息,数据块版本号等。(以下是其大概的构造,稍后会做解释)
―――――――――――――――――――――――――――
*** 2003-06-10 10:05:10.296
Start dump data blocks tsn: 2 file#: 3 minblk 13107 maxblk 13107
buffer tsn: 2 rdba: 0x00c03333 (3/13107)
scn: 0x0000.00105d22 seq: 0x05 flg: 0x00 tail: 0x5d220605
frmt: 0x02 chkval: 0x0000 type: 0x06=trans data
Block header dump: 0x00c03333
Object id on Block? Y
seg/obj: 0x6493 csc: 0x00.105d22 itc: 1 flg: O typ: 1 - DATA
fsl: 0 fnx: 0x0 ver: 0x01
――――――――――――――――――――――――――――
2. 事务列表区 事务列表去包括了在这个数据块内的事务,也就是我们知道的ITL(interested transaction list),从中我们可以知道XID(transaction id),UBA(undo block address)等信息(以下是其大概的构造,稍后会做解释)
---------------------------------------------------------------------------------
Itl Xid Uba Flag Lck Scn/Fsc
0x01 xid: 0x0009.012.00000002 uba: 0x00800c84.0000.25 ---- 1 fsc 0x0000.00000000
---------------------------------------------------------------------------------
3. 数据区,尾区 数据区顾名思义是真正存储数据的地方,在这里我们可以看到每一条记录。至于尾区,这里储存着数据块的版本号,与数据头信息区的版本号相对应,可以用来确定数据块前后是否一致。
(以下是其大概的构造,稍后会做解释)
―――――――――――――――――――――――――――
data_block_dump
===============
tsiz: 0x1fb8
hsiz: 0x14
pbl: 0x0f3f7444
bdba: 0x00c03333
flag=-----------
ntab=1
nrow=1
frre=-1
fsbo=0x14
fseo=0x1fb2
avsp=0x1f9b
tosp=0x1f9b
0xe:pti[0] nrow=1 offs=0
0x12:pri[0] offs=0x1fb2
block_row_dump:
tab 0, row 0, @0x1fb2
tl: 6 fb: --H-FL-- lb: 0x1 cc: 1
col 0: [ 2] c1 02(数据就在这里)
end_of_block_dump
End dump data blocks tsn: 2 file#: 3 minblk 13107 maxblk 13107
―――――――――――――――――――――――――――
下面我们来做一个完整的实验,首先创建一个新的表空间
SQL> create tablespace testblock datafile 'd:\oracle\oradata\test\testblock.ora'
size 100m;
表空间已创建。
创建一个新用户并指定默认表空间为testblock,临时表空间为temp
SQL> create user testblock identified by testblock default tablespace testblock
temporary tablespace temp;
用户已创建
SQL> grant create session to testblock;
授权成功。
SQL> grant resource to testblock;
授权成功。
SQL> connect testblock/testblock@test
已连接。
SQL> create table testblock (a number);
表已创建。
SQL> insert into testblock values(1);
已创建 1 行。
SQL> insert into testblock values(2);
已创建 1 行。
SQL> commit;
提交完成。
SQL> connect internal/oracle@test
已连接。
SQL> select header_file,header_block from dba_segments where segment_name='TESTBLOCK';
HEADER_FILE HEADER_BLOCK
Start dump data blocks tsn: 8 file#: 11 minblk 2 maxblk 2
buffer tsn: 8 rdba: 0x02c00002 (11/2)
scn: 0x0000.001148eb seq: 0x01 flg: 0x00 tail: 0x48eb1001
frmt: 0x02 chkval: 0x0000 type: 0x10=DATA SEGMENT HEADER - UNLIMITED
Extent Control Header
-----------------------------------------------------------------
Extent Header:: spare1: 0 space2: 0 #extents: 1 #blocks: 4
last map 0x00000000 #maps: 0 offset: 4128
Highwater:: 0x02c00004 ext#: 0 blk#: 1 ext size: 4
#blocks in seg. hdr's freelists: 1
#blocks below: 1
mapblk 0x00000000 offset: 0
Unlocked
Map Header:: next 0x00000000 #extents: 1 obj#: 25755 flag: 0x40000000
Extent Map
-----------------------------------------------------------------
0x02c00003 length: 4
nfl = 1, nfb = 1 typ = 1 nxf = 0
SEG LST:: flg: USED lhd: 0x02c00003 ltl: 0x02c00003
End dump data blocks tsn: 8 file#: 11 minblk 2 maxblk 2
――――――――――――――――――――――――――――――――――
这里我们看到表空间号是tsn: 8,数据文件号是file#: 11,相对数据块地址是rdba: 0x02c00002 (11/2),SCN为scn: 0x0000.001148eb(SCN Base=0011,SCN Wrap=48eb),尾区版本号为tail: 0x48eb1001(tail=SCN Wrap: 48eb + type: 0x10+ seq: 0x01),由于这个块是整个Segment的头,所以它还包含整个Segment的一些存储信息,比如extent数,block数,高水位地址Highwater:: 0x02c00004,自由列表信息hdr's freelists: 1等等。如果才用本地管理表空间,则此块的存储信息通过位图方式管理。
真正的数据是储存在下一个块也就是0x02c00002+1=0x02c00003,我们来看看究竟。
――――――――――――――――――――――――――――――――――
*** 2003-06-12 12:00:41.781
Start dump data blocks tsn: 8 file#: 11 minblk 3 maxblk 3
buffer tsn: 8 rdba: 0x02c00003 (11/3)
scn: 0x0000.001148ee seq: 0x01 flg: 0x02 tail: 0x48ee0601
frmt: 0x02 chkval: 0x0000 type: 0x06=trans data
Block header dump: 0x02c00003
Object id on Block? Y
seg/obj: 0x649b csc: 0x00.1148eb itc: 1 flg: O typ: 1 - DATA
fsl: 0 fnx: 0x0 ver: 0x01
Itl Xid Uba Flag Lck Scn/Fsc
0x01 xid: 0x0006.03f.000000da uba: 0x00800ad2.00ae.04 --U- 2 fsc 0x0000.001148ee
data_block_dump
===============
tsiz: 0x1fb8
hsiz: 0x16
pbl: 0x0ec77444
bdba: 0x02c00003
flag=-----------
ntab=1
nrow=2
frre=-1
fsbo=0x16
fseo=0x1fac
avsp=0x1f90
tosp=0x1f90
0xe:pti[0] nrow=2 offs=0
0x12:pri[0] offs=0x1fb2
0x14:pri[1] offs=0x1fac
block_row_dump:
tab 0, row 0, @0x1fb2
tl: 6 fb: --H-FL-- lb: 0x1 cc: 1
col 0: [ 2] c1 02
tab 0, row 1, @0x1fac
tl: 6 fb: --H-FL-- lb: 0x1 cc: 1
col 0: [ 2] c1 03
end_of_block_dump
End dump data blocks tsn: 8 file#: 11 minblk 3 maxblk 3
――――――――――――――――――――――――――――――――――
谜团解开了,ITL,数据都呈现出来了,开始分析!
Block header dump: 0x02c00003
Object id on Block? Y
seg/obj: 0x649b csc: 0x00.1148eb itc: 1 flg: O typ: 1 - DATA
fsl: 0 fnx: 0x0 ver: 0x01
数据块地址正是0x02c00002+1=0x02c00003
segment/object id为0x649b,转成10进制为25755,可以由obj#表中得知
SQL> select obj# from sys.obj$ where name='TESTBLOCK';
OBJ#
----------
25755
csc(SCN at last Block CleanOut): 0x00.1148eb表示最后一次块清除(Block CleanOut)时候的SCN,关于块清除的概念可以查阅Thomas Kyte 著的”expert one by one Oracle”。
itc: 1 表示Number of itl slots
flg: O 表示此块被放置在自由列表(freelist)中
typ: 1 – DATA,类型1表示数据,类