oracle block internal(block 内部结构分解)
Oracle block的详细物理结构图:
本文主要说明oracle block的物理结构,它是oracle的最小存储单元,由多个os数据块组成。主要由三个逻辑层组成(通过c语言描绘的结构,如下图一所示):the cache layer,the transaction layer,data layer。如果再细化,data layer又分为很多结构,如table directory,row directory,free space,row data等
Oracle的block被映射到SGA kcbh(kernel cache block header)的对应的block上 。
the cache layer:它是block header的第一部分,占用20个bytes。用于检查数据的正确性,即被读的block是否断裂或损坏。它包含如下结构
1. the data block address(DBA)
2. the block type (例如Table/Index, Rollback Segment, Temporary)
3. the block format (8i~9i 都是0x02 10.1.0 2k: 0x62 4k:0x82 8k:0xa2 16k:0xc2 (logfile 0x22 512 bytes))
4. a system change number(SCN)used for ordering purposes during recovery
the transaction layer: 用户存储数据块里transaction信息的,包含两部分信息
1. 一个是a fixed component ,KTBBH(TRANSACTION FIXED HEADER),包含关于数据块的类型,数据块的最 新cleanout时间,ITL(Interested Transcation List)的数量,空闲列表的链接,还有空闲空间lock。
2. 另一个是 a variable portion,KTBIT(TRANSACTION VARIABLE HEADER),包含一个进程在一个block里要编辑行所需要的ITLs。默认的包含一个表的数据块只有一个ITL,ITL的多少是通过存储参数INITRANS来设置的,设置较大的值会减少row data的可用空间,这个参数是可以动态修改的,但只影响新的block,对已经存在的block没有作用(可以用imp/exp,move等方法可以让其对存在的block起作用)
The data layer:包含data header 结构,KDBH(kernel data block header,是DATA HEADER,占用14bytes),和row data。其中data header包含表的数量(在表索引中,即table directory),数据行的数量,第一个空闲行的条目(在行索引中,即row directory),指向空闲区域的开始和结束的偏移量,可用的空闲空间。数据行是从block的底部开始insert的,伴随insert和delete操作,行数据是随机存储的。
如下图所示:
假设初始化5行数据,每行10bytes大小,按offsets排序是5,4,3,2,1。现在删除2,4行,再insert一行20bytes的数据,在row directory 中slot2被使用,但实际的row data存储在row5之上。这个时候再按offsets排序就是2,5,3,1 。随着你在数据块上的DML操作的越频繁,这种行的随机性就更强。
下面说下data block的设计,如下图所示
下面是oracle block的dump文件,结合上面这个图片来验证下oracle block的存储情况
Dump file e:/oracle/product/10.2.0/admin/test/udump/test_ora_4820.trc
Thu Aug 19 13:01:36 2010
ORACLE V10.2.0.4.0 - Production vsnsta=0
vsnsql=14 vsnxtr=3
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Windows XP Version V5.1 Service Pack 3, v.3300
CPU : 2 - type 586, 2 Physical Cores
Process Affinity : 0x00000000
Memory (Avail/Total): Ph:313M/1918M, Ph+PgF:2399M/3812M, VA:1289M/2047M
Instance name: test
Redo thread mounted by this instance: 1
Oracle process number: 21
Windows thread id: 4820, image: ORACLE.EXE (SHAD)
*** 2010-08-19 13:01:36.593
*** ACTION NAME:() 2010-08-19 13:01:36.578
*** MODULE NAME:(SQL*Plus) 2010-08-19 13:01:36.578
*** SERVICE NAME:(test) 2010-08-19 13:01:36.578
*** SESSION ID:(201.21830) 2010-08-19 13:01:36.578
Error: alter system dump datafile/tempfile: invalid input file # 0
*** 2010-08-19 13:02:41.375
Error: alter system dump datafile/tempfile: invalid input file # 0
*** 2010-08-19 13:03:17.296
Start dump data blocks tsn: 4 file#: 4 minblk 29347 maxblk 29347
buffer tsn: 4 rdba: 0x010072a3 (4/29347)
scn: 0x0000.009b876f seq: 0x01 flg: 0x04 tail: 0x876f2301
frmt: 0x02 chkval: 0x4671 type: 0x23=PAGETABLE SEGMENT HEADER
Hex dump of block: st=0, typ_found=1
Dump of memory from 0x0A2A8400 to 0x0A2AA400
A2A8400 0000A223 010072A3 009B876F 04010000 [#....r..o.......]
A2A8410 00004671 00000000 00000000 00000000 [qF..............]
A2A8420 00000000 00000001 00000008 00000A9C [................]
A2A8430 00000000 00000004 00000008 010072A5 [.............r..]
..r......
..r......
A2A9850 00000000 00000000 00000000 00000000 [................]
Repeat 185 times
A2AA3F0 00000000 00000000 00000000 876F2301 [.............#o.]
这里说明下TAIL用于验证block的完整性的,它是由SCNBase,block type,SCN seq number组成。
876F2301=876F(last two bytes of SCN Base)+ 23(type)+ 01(seq)
红色的字是offset(偏移量)
首先来看前20个bytes,也就是the cache layer,16进制的数据如下:
0000A223 010072A3 009B876F 04010000 00004671
第一和第二个字节是filler,也就是未被使用(
ub1 spare1_kcbh this field is no longer used (old inc#, now always 0)
ub1 spare2_kcbh this field is no longer used (old ts#, now always 0)
),未被定义(和前面的图有点出入)
第三个字节是frmt,一般是0x02,这里是0xa2,用掩码0x0f与运算可以取出0x02(掩码是为了保护敏感信息)
第四个字节是type,这里是23,代表PAGETABLE SEGMENT HEADER
第五个到第八个字节是rdba,这里是0x010072a3
第九个到第十二字节是SCNBase ,这里是 0x009B876F
第十三个字节是flg,这里是0x04
(
as defined in kcbh.h
#define KCBHFNEW 0x01 /* new block - zeroed data area */
#define KCBHFDLC 0x02 /* Delayed Logging Change advance SCN/seq */
#define KCBHFCKV 0x04 /* ChecK Value saved-block xor's to zero */
#define KCBHFTMP 0x08 /* Temporary block */
这是一个可以组合的值 也就是说有为 6 的时候是 2,4 两种情况的组合
)
第十四个字节seq,这里是 0x01。
(A sequence number incremented for each change to a block at the same SCN
A new SCN is allocated if the sequence number wraps.
同一个SCN影响这个block中的行数大于 254 行就会为这个事务分配一个新的SCN
如下面的操作就可能引起同一个SCN但影响的同一个block 中的行超过254行
"delete from table_name"
影响的行数(最大254) 是用从 0x01 到 0xfe 表示的
当这个byte 的数据为 0xff 的时候标志这个 block 坏调了---> ora-01578
Sequence number:
SEQ -> 0 /* non-logged changes - do not advance seq# */
SEQ -> (UB1MAXVAL-1)/* maximum possible sequence number */
SEQ -> (UB1MAXVAL) /* seq# to indicate a block is corrupt,equal to FF. soft corrupt*/
0xff : When present it indicates that the block has been marked as corrupt by Oracle. either by the db_block_checking functionality or the equivalent events (10210 for data blocks, 10211 for index blocks, and 10212 for cluster blocks) when making a database change, or by the DBMS_REPAIR.FIX_CORRUPT_BLOCKS procedure, or by PMON after an unsuccessful online block recovery attempt while recovering a failed process, or by RMAN during a BACKUP, COPY or VALIDATE command with the CHECK LOGICAL option. Logical corruptions are normally due to either recovery through a NOLOGGING operation, or an Oracle software bug.)
第十五和第十六字节是SCNWrap ,这里是0x0000
第十七和第十八字节是spare3_kcbh,这里未使用
第十九和第二十字节是checksum,这里是0x4671
正好和dump的内容一样
buffer tsn: 4 rdba: 0x010072a3 (4/29347)
scn: 0x0000.009b876f seq: 0x01 flg: 0x04 tail: 0x876f2301
frmt: 0x02 chkval: 0x4671 type: 0x23=PAGETABLE SEGMENT HEADER
相关说明:
Rdba:block的相对地址(DBA)
Scn: SCN number
Seq:sequence number incremented for each change made to the block at the same SCN
Flg:flag
Tail:验证block的完整性,通过检查block的开始和结束是否是同一版本
Frmt:block format 通常是0x02
Chkval:如果db_block_checksum=true时,block的核查值
Type:block的类型,如data,index等
到此block的前20bytes都已经解读了,然后再看看紧跟其后的kttbh 的24bytes内容解读
BBED> p ktbbh
struct ktbbh, 48 bytes @20
ub1 ktbbhtyp @20 0x01 (KDDBTDATA)
union ktbbhsid, 4 bytes @24
ub4 ktbbhsg1 @24 0x0000001c
ub4 ktbbhod1 @24 0x0000001c
struct ktbbhcsc, 8 bytes @28
ub4 kscnbas @28 0x805c12df
ub2 kscnwrp @32 0x0000
b2 ktbbhict @36 1
ub1 ktbbhflg @38 0x02 (NONE)
ub1 ktbbhfsl @39 0x00
ub4 ktbbhfnx @40 0x00000000
struct ktbbhitl[0], 24 bytes @44
struct ktbitxid, 8 bytes @44
ub2 kxidusn @44 0x0002
ub2 kxidslt @46 0x0025
ub4 kxidsqn @48 0x0006e714
struct ktbituba, 8 bytes @52
ub4 kubadba @52 0x00801ba0
ub2 kubaseq @56 0xaa14
ub1 kubarec @58 0x10
ub2 ktbitflg @60 0x2001 (KTBFUPB)
union _ktbitun, 2 bytes @62
b2 _ktbitfsc @62 0
ub2 _ktbitwrp @62 0x0000
ub4 ktbitbas @64 0x805c12e0
以下是16进制文件内容:
Start dump data blocks tsn: 4 file#: 4 minblk 29348 maxblk 29348
buffer tsn: 4 rdba: 0x010072a4 (4/29348)
scn: 0x0000.00e66a1e seq: 0x02 flg: 0x06 tail: 0x6a1e0602
frmt: 0x02 chkval: 0x4590 type: 0x06=trans data
Hex dump of block: st=0, typ_found=1
Dump of memory from 0x061E8400 to 0x061EA400
61E8400 0000A206 010072A4 00E66A1E 06020000 [.....r...j......]
61E8410 00004590 00000001 0000ED65 009B8769 [.E......e...i...]
61E8420 00000000 00320003 010072A1 0000FFFF [......2..r......]
61E8430 00000000 00000000 00000000 00008000 [................]
61E8440 009B8769 00190001 00001B03 0080027B [i...........{...]
61E8450 002C0E55 00002001 00E66A1E 00000000 [U.,.. ...j......]
61E8460 00000000 00000000 00000000 00000000 [................]
61E8470 00000000 00000000 00000000 00090100 [................]
61E8480 0024FFFF 1C291C4D 00001C29 1F1E0009 [..$.M.).).......]
61E8490 1E6C1EC3 1DB71E13 1D021D5B 1C4D1CA7 [..l.....[.....M.]
61E84A0 00000000 00000000 00000000 00000000 [
.
.
.
61EA3E0 38302D35 3A30332D 353A3331 30333A30 [5-08-30:13:50:30]
61EA3F0 4C415605 4E014449 4E014E01 6A1E0602 [.VALID.N.N.N...j]
其中buffer tsn: 数据文件对应的 tablespace 的 number ,这只是dump文件中记录的数据而已,block 中是没有记录 tablespace 的number 的
第21-24字节,即0x00000001,表示typ ,占4个bytes
(
1 : DATA , 2: index
改成3了在10.1.0 上引起了ora-600[2032]然后ORA-27101: shared memory realm does not exist
oracle进行查询的时候是根据 obj$表中的情况来判断对象的类型的,不是根据这个typ
也就是说如果有一个表但改变表中block的这个标志位,一样可以查询出数据来,
但dump block 时会出错,ORA-00600: 内部错误代码,自变量: [4555], [0], [], [], [], [], [], []
错误中的 [0] 就是typ对应的数据
在10G中改变它后update这个block的数据commit可以但rollback的报错)
第25-28字节,即0x0000ED65,表示seg/obj,占4个字节
第29-36字节,即 0x009B8769.00000000,表示csc ,占6个字节(The SCN at which the last full cleanout was performed on the block)
第37字节,即0x00 表示 fsl (Index to the first slot on the ITL freelist. ITL TX freelist slot)
第38字节,即0x32 表示flg
(
indicates that the block is on a freelist. Otherwise the flag is -
9i 的ASSM 的情况下这个值为 E
ixora 上说他占用 2 bytes 但我下面的试验和他的结果有一定的出入
我观察到的情况是 : Object id on Block? Y flg: O ver: 0x01
上面的3项是用同一个 byte 来表示的
flg: O ver: 0x01 Object id on Block? Y
从我的观察中 dump 出来的文件中 flg ver Object id on Block
他们共同占用的这个一个字节 他的规律可以从下面的情况看出
2进制数据 flg ver Object id on Block?
0x00 - 0x00 N
0x01 0 0x00 N
0x02 - 0x01 Y
0x03 0 0x01 Y
0x04 - 0x02 Y
0x05 0 0x02 Y
0x06 - 0x03 Y
0x07 0 0x03 Y
0x08 - 0x04 N
0x09 0 0x04 N
0x0a - 0x05 Y
0x0b 0 0x05 Y
0x0c - 0x06 Y
0x0d 0 0x06 Y
0x0e - 0x07 Y
0x0f 0 0x07 Y
0x10 ... 类似上面的循环了 这种情况在9i上已经改变因为ASSM的出现
)
第39-40字节,即0x0003 表示 itc ,占2个字节。用0x00ff掩码取值,值为3(ITL 条目的个数 max 255超过会报ORA-02207 ORA-00060 ORA-00054 可能是没空间分配itl条目了或它的争用引起的,在8i中 INITRANS default为1 , 9.2.0中 INITRANS default为2)
第41-44字节,即0x010072A1 表示 (自由列表中下一块的地址 Null if this block is not on a freelist)
从44字节以后就是ITL的记录,每个itl所占24bytes
第45-52字节,即0x0000.FFFF.00000000,表示xid
(
Transaction ID (UndoSeg.Slot.Wrap)
值可以用select XIDUSN, XIDSLOT,XIDSQN from v$transaction;查到
This is comprised of the rollback segment number (2 bytes), the slot number
in the transaction table of that rollback segment (2 bytes), and the number
of times use of that transaction table has wrapped (4 bytes).
)
第53-60字节,即0x00000000.000000.00,表示uba
(
Undo address (UndoDBA.SeqNo.RecordNo)
The location of the undo for the most recent change to this block by this transaction. This is comprised of the DBA of the rollback segment block (4 bytes), the sequence number (2 bytes), and the record number for the change in that undo block (1 byte), plus 1 unused byte.
)
第63-64字节,即0x8000 ,表示lck flag
(
Lck 锁定的row数 这里还用到了下一个 byte 的数据
2 对应的二进制表示为 0010 正好和dump文件中的 --U- 吻合
flag 1 nibble
C = Committed; U = Commit Upper Bound; T = Active at CSC; B = Rollback of this UBA gives before image of the ITL.
---- = transaction is active, or committed pending cleanout
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 = transaction was still active at block cleanout SCN
Lck 3 nibbles
The number of row-level locks held in the block by this transaction.)
第61-62和65-68字节,即 0x0000.009B8769 表示Scn/Fsc:
(
If the transaction has been cleaned out, this is the commit SCN or an upper bound thereof. Otherwise the leading two bytes contain the free space credit for the transaction - that is, the number of bytes freed in the block by the transaction
Scn = SCN of commited TX; Fsc = Free space credit (bytes)
)
再往下分析,Block header dump: 0x010072a4
Object id on Block? Y
seg/obj: 0xed65 csc: 0x00.9b8769 itc: 3 flg: E typ: 1 - DATA
brn: 0 bdba: 0x10072a1 ver: 0x01 opc: 0
inc: 0 exflg: 0
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0xffff.000.00000000 0x00000000.0000.00 C--- 0 scn 0x0000.009b8769
0x02 0x0001.019.00001b03 0x0080027b.0e55.2c --U- 1 fsc 0x0000.00e66a1e
0x03 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
因为这里有三个itls,所有共占用24×3=72bytes空间,再加上20+24+8(这个可能是保留的,具体做什么,不是很清楚?),总124字节
16进制文件如下:
61E8470 00000000 00000000 00000000 00090100 [................]
61E8480 0024FFFF 1C291C4D 00001C29 1F1E0009 [..$.M.).).......]
61E8490 1E6C1EC3 1DB71E13 1D021D5B 1C4D1CA7 [..l.....[.....M.]
第125字节,即0x00 表示flag
(
N=pctfree hit(clusters), F=don't put on free list
K=flushable cluster keys. 当然还有别的标记: A ...
)
第126字节,即0x09,表示nrow (block 有多少行数据)
第127字节,即0x01,表示ntab (这block中有几个table的数据 cluster这个就可能大于1)
第128-129字节,即0x0000,表示frre (First free row index entry. -1=you have to add one.)
第130字节,即0x24,表示fsbo
(Free Space Begin offset 出去row dict 后面的可以放数据的空间的起始位置
也可以看成是从这个区域的开始"flag"到最后一个 "row offs"占用的空间)
第135-136字节,即 0x1C4D,表示fseo
(
Free Space End offset ( 9.2.0 )参与db_block_checking的计算剩余空间
select 的时候oracle不是简单的根据offset定位row.这个值也是参与了定位row的
)
第139-140字节,即0x1C29,表示tosp(Total available space when all TXs commit ( 9.2.0 )参与db_block_checking)
第133-134字节,即0x1C29,表示avsp(Available space in the block (pctfree and pctused) ORA-01578)
Oracle的dsi文档里和bbed查看block的结构,都表明kdbh占14字节,但我的这个测试和其有些出入,希望高人指出
其中第141-142字节,即0x1F1E,表示offsets (偏移量 用 cluster 的时候可以看出值)
第143-144字节,即0x0009,表示nrow(这个table有多少行数据)
和下面的Block的dump文件是对应符合的
data_block_dump,data header at 0x61e847c
//data_block_dump,data header at 0x61e847c
//其实这个block不是直接从 data buffer 中 dump 出来的这个表示真正dump时 block 的数//据区的起始位置
//也就是下面这部分开始的位置
=============== //// tsiz: hsiz: pbl: bdba: 在数据文件都是没有存储的
tsiz: 0x1f80 //// Total data area size ---8k的block: 8192-20(block head)-24(Transaction Header)-24*2(一个事务条)-8(我不太清楚的8个字节)-4(block tail)=8072(0x1f80)
hsiz: 0x24 //// Data header size 数据块头20个字节+数据块尾4个字节=24字节(0x14)
pbl: 0x061e847c //// Pointer to buffer holding the block
bdba: 0x010072a476543210
flag=--------
ntab=1 ---这block中有几个table的数据 cluster这个就可能大于1
nrow=9 ---block 有多少行数据
frre=-1
fsbo=0x24
fseo=0x1c4d
avsp=0x1c29
tosp=0x1c29
0xe:pti[0] nrow=9 offs=0
0x12:pri[0] offs=0x1f1e
0x14:pri[1] offs=0x1ec3
0x16:pri[2] offs=0x1e6c
0x18:pri[3] offs=0x1e13
0x1a:pri[4] offs=0x1db7
0x1c:pri[5] offs=0x1d5b
0x1e:pri[6] offs=0x1d02
0x20:pri[7] offs=0x1ca7
0x22:pri[8] offs=0x1c4d
block_row_dump:
tab 0, row 0, @0x1f1e
tl: 98 fb: --H-FL-- lb: 0x2 cc: 15
col 0: [ 5] c4 02 07 4c 0c
col 1: [ 4] 32 30 30 31
col 2: [ 3] 53 59 53
col 3: [16] 53 4e 41 50 5f 4c 4f 41 44 45 52 54 49 4d 45 24
col 4: *NULL*
col 5: [ 3] c2 02 3f
col 6: [ 3] c2 02 3e
col 7: [ 5] 54 41 42 4c 45
col 8: [ 7] 78 69 08 1e 0e 33 1f
col 9: [ 7] 78 69 08 1e 0e 33 1f
col 10: [19] 32 30 30 35 2d 30 38 2d 33 30 3a 31 33 3a 35 30 3a 33 30
col 11: [ 5] 56 41 4c 49 44
col 12: [ 1] 4e
col 13: [ 1] 4e
col 14: [ 1] 4e
1.gif
2.gif
3.gif
4.gif