本帖最后由 ubotutwin 于 2012-2-1 10:04 编辑
BBED> setblock 377 BLOCK# 377
BBED> map
File: /home/oracle/vie.pdf (1)
Block: 377 Dba:0x00400179------------------------------------------------------------
Unlimited Data Segment Header
struct kcbh, 20 bytes a0
struct ktech, 72 bytes a20
struct ktemh, 16 bytes a92
struct ktetb[1], 8 bytes a108
struct ktshc, 8 bytes a4148
struct ktsfs_seg[1], 20 bytes a4156
struct ktsfs_txn[16], 320 bytes a4176
ub4 tailchk a8188
dump输出:
*** 2011-10-1122:29:03.808
*** SERVICENAME:(SYS$USERS) 2011-10-11 22:29:03.797
*** SESSIONID:(124.22380) 2011-10-11 22:29:03.797
Start dump datablocks tsn: 0 file#: 1 minblk 377 maxblk 377
buffer tsn: 0rdba: 0x00400179 (1/377)
scn:0x0000.0000014a seq: 0x01 flg: 0x04 tail: 0x014a1001
frmt: 0x02chkval: 0xe733 type: 0x10=DATA SEGMENT HEADER - UNLIMITED
Hex dump ofblock: st=0, typ_found=1
Dump of memoryfrom 0x000000000F1DB600 to 0x000000000F1DD600
00F1DB6000000A210 00400179 0000014A 04010000 [....y.a.J......]…………省略…………..
00F1DD5F000000000 00000000 00000000 014A1001 [....... .....J.] Extent Control Header
----------------------------------------------------------------- Extent Header:: spare1: 0 spare2: 0 #extents: 1 #blocks: 7
last map 0x00000000 #maps: 0 offset: 4128
Highwater:: 0x0040017d ext#: 0 blk#: 3 ext size: 7 #blocks in seg. hdr's freelists: 1
#blocks below: 3
mapblk 0x00000000 offset: 0 Unlocked
Map Header:: next 0x00000000 #extents: 1 obj#: 56 flag: 0x40000000 Extent Map
-----------------------------------------------------------------
0x0040017a length: 7
nfl = 1, nfb = 1 typ = 1 nxf = 0 ccnt = 3
SEG LST:: flg: USED lhd: 0x0040017c ltl: 0x0040017c
End dump datablocks tsn: 0 file#: 1 minblk 377 maxblk 377
dd输出:
00000000h: 10A2 00 00 79 01 40 00 4A 01 00 00 00 00 01 04 ; .?.y.a.J.. ....
00000010h: 33E7 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; 3?.. ..... ....
00000020h: 0000 00 00 01 00 00 00 07 00 00 00 20 10 00 00 ; .. ..... ... ...
00000030h: 0000 00 00 03 00 00 00 07 00 00 00 7D 01 40 00 ; .. ..... ...}.a.
00000040h: 0000 00 00 00 00 00 00 01 00 00 00 03 00 00 00 ; .. ..... .......
00000050h: 0000 00 00 00 00 00 00 00 00 00 00 01 00 00 00 ; .. ..... .......
00000060h: 0000 00 00 38 00 00 00 00 00 00 40 7A 01 40 00 ; ....8.. ...az.a.
00000070h: 0700 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .. ..... .......
00000080h: 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .. ..... .......
00000090h: 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .. ..... .......
000000a0h: 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .. ..... .......…………………省略……………………..
377块的block type为0x10,表示该块是Data segment header block (unlimited extents, no freelist groups),就是mssm下的segment header,而assm的segment header的block type为0x24,表示PAGETABLEEXTENT MAP BLOCK(bbed工具目前不支持assm相关的segment header和三级位图块)。
结合观察三种工具的输出。bbed中的“structktetb[1], 8 bytes a108” 对应的就是oracle dump输出的extent map,该结构体记录了segment中的extent的首地址。这里有一点特别的地方,在进行分析的过程中发现,存放在assm表空间中的segment的header block中的extent map包涵了三级位图的块,就是说assm管理的下的extent map覆盖整个segment占用的块,而存放在mssm表空间中的segment的header block中的extent map,仅包涵segment中存放数据的块,没有包涵段头块本身。由于sys.bootstrap$表处于system表空间中,因此采用的是mssm的管理方式。Assm与mssm下的extent map格式是相同的,每个extent的信息占用8字节存储,前4字节记录该extent中的第一个块的dba(data block address),后4字节记录该extent包涵的块的个数,使用bbed对其进行观察:
BBED> pktetb
structktetb[0], 8 bytes a108
ub4 ktetbdba a108 0x0040017a ub4 ktetbnbk a112 0x00000007
与dump文件中的extent map吻合。
在mssm管理下的extent map是在块108偏移量的位置,那么这个位置是否是固定的,我没有找到相关权威资料,因此进行如下分析:首先从不同的库,取不同数据量的表的segment header block,发现偏移量相同,然后用bbed分析ktetb结构体前面的几个结构体变量:
BBED> map /v
File: /home/oracle/vie.pdf (1)
Block: 377 Dba:0x00400179------------------------------------------------------------
Unlimited Data Segment Header
struct kcbh, 20 bytes a0
ub1 type_kcbh a0
ub1 frmt_kcbh a1
ub1 spare1_kcbh a2
ub1 spare2_kcbh a3
ub4 rdba_kcbh a4
ub4 bas_kcbh a8
ub2 wrp_kcbh a12
ub1 seq_kcbh a14
ub1 flg_kcbh a15
ub2 chkval_kcbh a16
ub2 spare3_kcbh a18
struct ktech, 72 bytes a20
ub4 spare1_ktech a20
word tsn_ktech a24
ub4 lastmap_ktech a28
ub4 mapcount_ktech a32
ub4 extents_ktech a36
ub4 blocks_ktech a40
ub2 mapend_ktech a44
struct hwmark_ktech, 32 bytes a48
struct locker_ktech, 8 bytes a80
ub4 flag_ktech a88
struct ktemh, 16 bytes a92
ub4 count_ktemh a92 ub4 next_ktemh a96
ub4 obj_ktemh a100
ub4 flag_ktemh a104
可见前三个结构体都不是数组类型,所以目前判断ktetb的偏移量应该是在数据库版本一定的情况下是固定的存放在块头偏移108的位置。
继续进行观察。将extent map中的dba“0x0040017a”进行转换,其指向1号文件的378号数据块。按377块extent map中所记录,sys.bootstrap$表存储于1号文件378号数据块开始的连续7个数据块中,且ub4 next_ktemh a96的值为0x00000000,因此所有数据都存储在这7个数据块中。
继续深入观察378号数据块就能得到sys.bootstrap$表的真实数据:
bbed输出:
BBED> setblock 378 BLOCK# 378
BBED> map
File: /home/oracle/vie.pdf (1)
Block: 378 Dba:0x0040017a------------------------------------------------------------
KTB Data Block (Table/Cluster)
struct kcbh, 20 bytes a0
struct ktbbh, 48 bytes a20
struct kdbh, 14 bytes a68
struct kdbt[1], 4 bytes a82
sb2 kdbr[24] a86
ub1 freespace[1158] a134
ub1 rowdata[6896] a1292
ub4 tailchk a8188
oracledump输出:
Start dump data blocks tsn: 0 file#: 1minblk 378 maxblk 378
buffer tsn: 0 rdba: 0x0040017a (1/378)
scn: 0x0000.0000015d seq: 0x01 flg:0x06 tail: 0x015d0601
frmt: 0x02 chkval: 0x13d5 type:0x06=trans data
Hex dump of block: st=0, typ_found=1
Dump of memory from 0x000000001E849600to 0x000000001E84B600
01E849600 0000A206 0040017A 0000015D06010000 [....z.a.].. ....]
01E849610 000013D5 00000001 00000038000000C7 [.. .....8.. ....]
01E849620 00000000 00020001 0000000000220000 [.. ..... ,...".],
01E849630 00000002 00400182 000C000200002018 [.. ...a.. ... ..]
……………………………省略部分内容………………………
Block header dump: 0x0040017a
Object id on Block? Y
seg/obj: 0x38 csc: 0x00.c7 itc: 1 flg: - typ: 1 - DATA
fsl: 0 fnx: 0x0 ver: 0x01
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x0000.022.00000002 0x00400182.0002.0c --U- 24 fsc 0x0000.0000015d
data_block_dump,data header at0x1e849644
===============
tsiz: 0x1fb8
hsiz: 0x42
pbl: 0x1e849644
bdba: 0x0040017a
76543210
flag=--------
ntab=1
nrow=24
frre=-1
fsbo=0x42
fseo=0x4c8
avsp=0x486
tosp=0x486
0xe:pti[0] nrow=24 offs=0
0x12:pri[0] offs=0x1fa3
0x14:pri[1] offs=0x1f1a
0x16:pri[2] offs=0x1d95
0x18:pri[3] offs=0x1ccd
0x1a:pri[4] offs=0x1b4e
0x1c:pri[5] offs=0x1a7a
0x1e:pri[6] offs=0x19ad
0x20:pri[7] offs=0x1749
0x22:pri[8] offs=0x167b
0x24:pri[9] offs=0x15b3
0x26:pri[10] offs=0x14d6
0x28:pri[11] offs=0x140a
0x2a:pri[12] offs=0x12ef
0x2c:pri[13] offs=0x1205
0x2e:pri[14] offs=0x110e
0x30:pri[15] offs=0xf38
0x32:pri[16] offs=0xe68
0x34:pri[17] offs=0xd91
0x36:pri[18] offs=0xc79
0x38:pri[19] offs=0x969
0x3a:pri[20] offs=0x89c
0x3c:pri[21] offs=0x65e
0x3e:pri[22] offs=0x58e
0x40:pri[23] offs=0x4c8
block_row_dump:
tab 0, row 0, a0x1fa3
tl: 21 fb: --H-FL-- lb: 0x1 cc: 3
col 0: [ 3] 3e 64 66
col 1: [ 3] 3e 64 66
col 2: [ 9] 38 2e 30 2e 30 2e 30 2e30
tab 0, row 1, a0x1f1a
tl: 137 fb: --H-FL-- lb: 0x1 cc: 3
col 0: [ 1] 80
col 1: [ 1] 80
col 2: [129]
43 52 45 41 54 45 20 52 4f 4c 4c 42 41 43 4b20 53 45 47 4d 45 4e 54 20 53
59 53 54 45 4d 20 53 54 4f 52 41 47 45 20 2820 20 49 4e 49 54 49 41 4c 20
31 31 32 4b 20 4e 45 58 54 20 31 30 32 34 4b20 4d 49 4e 45 58 54 45 4e 54
53 20 31 20 4d 41 58 45 58 54 45 4e 54 53 2033 32 37 36 35 20 4f 42 4a 4e
4f 20 30 20 45 58 54 45 4e 54 53 20 28 46 494c 45 20 31 20 42 4c 4f 43 4b
20 39 29 29
……………………………..省略………………………
dd输出:
00000000h: 06 A2 00 00 7A 01 40 00 5D 01 00 00 00 00 01 06 ; .?.z.a.]......
00000010h: D5 13 00 00 01 00 00 00 38 00 00 00 C7 00 00 00 ; ?.. ...8...?..
00000020h: 00 00 00 00 01 00 02 00 00 00 00 00 00 00 22 00 ; ....... .....".
00000030h: 02 00 00 00 82 01 40 00 02 00 0C 00 18 20 00 00 ; ....?a..... ..
00000050h: 86 04 00 00 18 00 A3 1F 1A 1F 95 1D CD 1C 4E 1B ;?....?..??N.
00000060h: 7A 1A AD 19 49 17 7B 16 B3 15 D6 14 0A 14 EF 12 ;z.?I.{.??..?
00000070h: 05 12 0E 11 38 0F 68 0E 91 0D 79 0C 69 09 9C 08 ;....8.h.?y.i.?
00000080h: 5E 06 8E 05 C8 04 00 00 00 00 00 00 00 00 00 00 ; ^.??.........
00000090h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ....... .......
000000a0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ....... .......
00000500h: 00 00 00 00 00 00 00 00 00 00 00 00 2C 01 03 02 ; ....... ...,...
…………………………..省略部分内容………………………….
00000510h: C1 08 02 C1 08 BC 43 52 45 41 54 45 20 49 4E 44 ; ?.?糃REATE IND
00000520h: 45 58 20 49 5F 54 53 23 20 4F 4E 20 43 4C 55 53 ; EXI_TS# ON CLUS
00000530h: 54 45 52 20 43 5F 54 53 23 20 50 43 54 46 52 45 ; TERC_TS# PCTFRE
00000540h: 45 20 31 30 20 49 4E 49 54 52 41 4E 53 20 32 20 ; E 10INITRANS 2
00000550h: 4D 41 58 54 52 41 4E 53 20 32 35 35 20 53 54 4F ;MAXTRANS 255 STO
00000560h: 52 41 47 45 20 28 20 20 49 4E 49 54 49 41 4C 20 ; RAGE( INITIAL
00000570h: 36 34 4B 20 4E 45 58 54 20 31 30 32 34 4B 20 4D ; 64KNEXT 1024K M
00000580h: 49 4E 45 58 54 45 4E 54 53 20 31 20 4D 41 58 45 ;INEXTENTS 1 MAXE
00000590h: 58 54 45 4E 54 53 20 32 31 34 37 34 38 33 36 34 ; XTENTS214748364
000005a0h: 35 20 50 43 54 49 4E 43 52 45 41 53 45 20 30 20 ; 5PCTINCREASE 0
000005b0h: 4F 42 4A 4E 4F 20 37 20 45 58 54 45 4E 54 53 20 ; OBJNO 7EXTENTS
……………………………省略……………………………………
到这里就是非常熟悉的数据块的内容了。观察dd输出可见,由于系统字典全部为ascii码字符,所以已经可以看到表中内容的明文了。
在378号块中,从structkdbh, 14 bytes a68开始记录的就是块内数据行的相关字典信息,kdbh数据结构的偏移量为:20+24+ ktbbh. Ktbbhict*24。具体含义为kcbh结构体20字节+ktbbh结构体中的固定长度部分24字节+ktbbh中ktbbhitl数组长度(每个itl槽占24字节,itl槽个数记录在ktbbhict变量中)。注:这个偏移量公式只适用于mssm表空间,assm稍有区别,后详述。继续观察kdbh结构体:
BBED> p kdbh
struct kdbh, 14bytes a68 ub1 kdbhflag a68 0x00 (NONE)
b1 kdbhntab a69 1
b2 kdbhnrow a70 24
sb2 kdbhfrre a72 -1
sb2 kdbhfsbo a74 66
sb2 kdbhfseo a76 1224
b2 kdbhavsp a78 1158
b2 kdbhtosp a80 1158
这里有两个和本文有关的变量;1、kdbhntab,块里存放数据属于几个表,普通表这里是1,超过1是簇表。2、Kdbhnrow,块里存放的数据行数。
接下来是struct kdbt[1], 4 bytes a130数组,该数组的偏移量为kdbh的偏移量+14(kdbh结构体的长度)。该块中存放的数据所属的每个表都要在kdbt数组里占用4字节(一个数组元素)存储相关信息,对于普通表来说,数据块内存储的数据都属于同一个表,因此这个数组的长度肯定为1。
从sb2 kdbr[24] a86开始记录的就是块内存放的数据行的行偏移量表,每个数据行在行偏移量表里占2字节。该数组本身的物理偏移量为:kdbh的偏移量+14(kdbh结构体的长度)+kdbh结构体中kdbhntab变量的值*4(每个表占4字节)。具体到378数据块就是68+14+1*4=86。在dd输出中找到offset 86的位置:
00000000h: 06 A200 00 7A 01 40 00 5D 01 00 00 00 00 01 06 ; .?.z.a.].. ....
00000010h: D5 1300 00 01 00 00 00 38 00 00 00 C7 00 00 00 ; ?.. ...8...?..
00000020h: 00 0000 00 01 00 02 00 00 00 00 00 00 00 22 00 ; .. ..... .....".
00000030h: 02 0000 00 82 01 40 00 02 00 0C 00 18 20 00 00 ; ....?a.. ... ..
00000040h: 5D 0100 00 00 01 18 00 FF FF 42 00 C8 04 86 04 ; ].. ....B.??
00000050h: 86 0400 00 18 00 A3 1F 1A1F 95 1D CD 1C 4E 1B ; ?....?..??N.
00000060h: 7A 1AAD 19 49 17 7B 16 B3 15 D6 14 0A 14 EF 12 ; z.?I.{.??..?
00000070h: 05 120E 11 38 0F 68 0E 91 0D 79 0C 69 09 9C 08 ; ....8.h.?y.i.?
00000080h: 5E 068E 05 C8 04 00 00 00 00 00 00 00 00 00 00 ; ^.??.. .......
00000090h: 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .. ..... .......
000000a0h: 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .. ..... .......上面红色白底标注的就是378块offset 86位置。我进行分析所用数据库安装在linux操作系统上,linux操作系统采用Little Endian存储模式,因此一个变量中的各个字节之间的顺序和正常阅读顺序是颠倒的,因此该位置的值是1F A3,与dump文件中行列表中的第一行相吻合。
0x1FA3转换为10进制为8099,前面提到,该偏移量是在kdbh开始计算,因此要加上68,899+68=8167,观察dd输出中8167位置:
……………………………省略前面部分…………………………….
00001f90h: 49 4E49 54 49 41 4C 20 31 31 32 4B 20 4E 45 58 ; INITIAL 112K NEX
00001fa0h: 54 2031 30 32 34 4B 20 4D 49 4E 45 58 54 45 4E ; T 1024K MINEXTEN
00001fb0h: 54 5320 31 20 4D 41 58 45 58 54 45 4E 54 53 20 ; TS 1 MAXEXTENTS
00001fc0h: 33 3237 36 35 20 4F 42 4A 4E 4F 20 30 20 45 58 ; 32765 OBJNO 0 EX
00001fd0h: 54 454E 54 53 20 28 46 49 4C 45 20 31 20 42 4C ; TENTS (FILE 1 BL
00001fe0h: 4F 434B 20 39 29 29 2C 01 03 03 3E 64 66 03 3E ; OCK9)),...>df.>
00001ff0h: 6466 09 38 2E 30 2E 30 2E 30 2E 30 01 06 5D 01 ; df.8.0.0.0.0..].
以上红色白底部分就是8167偏移量位置对应的数据,块最后4个字节“01 06 5D 01”是块的校验信息,不属于数据行内容。从这里可以看出,oracle在将数据写入数据块时是从下往上进行写入的,这是在编程中经常用到的一种数据存储设计方式,在一个固定大小的存储空间中存储不同的数据结构,那么就采用一种数据从上向下增长,另一种数据从下向上增长,这样可以最大限度的利用存储空间。
进一步观察这段数据:
2C01 03 03 3E 64 66 03 3E 64 66 09 38 2E 30 2E 30 2E 30 2E 30这一行字符,就是该表第一行的全部数据。第一个字节的2C表示该行的row flag,采用的是符号位的存储方式,即该字节的8个比特位分别代表块的一种属性,该比特位为1表示该属性对于该块成立。2C对应为00101100与dump文件中该行的flag相吻合:
tab 0, row 1, a0x1f1a
tl: 137 fb: --H-FL-- lb:0x1 cc: 3
col 0: [ 1] 80
col 1: [ 1] 80
col 2: [129]
4352 45 41 54 45 20 52 4f 4c 4c 42 41 43 4b 20 53 45 47 4d 45 4e 54 20 53
……………………………省略………………………………..
2C即--H-FL--中的H、F、L分别表示head data piece、first data piece、last data piece,这里表示该行数据的以上三个piece全部存储在当前的这个位置,没有行链接现象。如果有行链接,则数据行的三个piece会分别存储到不同的块内。Flag的其他位以后做详细分析。
2C 0103 03 3E 64 66 03 3E 64 66 09 38 2E 30 2E 30 2E 30 2E 30 第二个字节的01表示行上的锁的状态。
2C 01 0303 3E 64 66 03 3E 64 66 09 38 2E 30 2E 30 2E 30 2E 30 第三个字节的03表示行内字段的数量,这里要注意的是flag、lock信息、column count三中信息不一定固定为三个字节,在簇表等其他情况下,可能是3字节或者9字节或者19字节等等不同长度,需要针对segment类型分别分析。
2C 01 03 033E 64 66 03 3E 64 66 09 38 2E 30 2E 30 2E 30 2E 30 第四个字节的03表示之后这个字段(行内存储的第一个字段)占用3个字节存储。提取后面三个字节的内容“3E 64 66”,与sys.bootstrap$表中第一行的第一个字段的值“-1”吻合:
SQL> select dump(-1,16) from dual;
DUMP(-1,16)
---------------------
Typ=2 Len=3: 3e,64,66
2C 01 03 03 3E 64 66 03 3E 64 66 09 38 2E 30 2E30 2E 30 2E 30
第八个字段的03表示第二个字段占用三个字节。
2C 01 03 03 3E 64 66 03 3E 64 66 09 38 2E 30 2E 30 2E30 2E 30
第十二个字节的09表示第三个字段占用9个字节。
这里所举例的bootstrap$表的所有字段都是非空的,如果一行中非末尾字段为空,oracle加入一个值为0xff的字节,如果行最后一个字段为空,那么该字段不记录,就是说如果一行的最后一个字节为空,那么行头记录的字段个数会比结尾字段不为空的行少。
如果一个字段的长度大于256字节,oracle将占用三个字节来记录该字段长度,且这三个字节的第一个字节为“0xfe”。
从这里也可以看出,oracle在一行数据中的各个字段是按照队列的方式存放的,且队列的各个元素不固定长度,所以,当oracle需要读取某行数据的某个字段的值时,需要遍历该字段前的所有字段。因此,在oracle表的设计阶段,根据业务,将使用频繁的列尽量放在表的前面,可以减小数据库内存操作的压力,提升sql执行速度。
再分析索引簇的存储方式。以SYS.SEG$表为例,sys.bootstrap$中该表的定义为:
CREATE TABLE SEG$("FILE#" NUMBER NOTNULL,"BLOCK#" NUMBER NOT NULL,"TYPE#" NUMBER NOTNULL,"TS#" NUMBER NOT NULL,"BLOCKS" NUMBER NOTNULL,"EXTENTS" NUMBER NOT NULL,"INIEXTS" NUMBER NOTNULL,"MINEXTS" NUMBER NOT NULL,"MAXEXTS" NUMBER NOTNULL,"EXTSIZE" NUMBER NOT NULL,"EXTPCT" NUMBER NOTNULL,"USER#" NUMBER NOT NULL,"LISTS"NUMBER,"GROUPS" NUMBER,"BITMAPRANGES" NUMBER NOTNULL,"CACHEHINT" NUMBER NOT NULL,"SCANHINT" NUMBER NOTNULL,"HWMINCR" NUMBER NOT NULL,"SPARE1"NUMBER,"SPARE2" NUMBER) STORAGE ( OBJNO 14 TABNO 2) CLUSTER C_FILE#_BLOCK#(TS#,FILE#,BLOCK#)通过红色字体白底部分,可见该表属于C_FILE#_BLOCK#簇,而C_FILE#_BLOCK#簇在sys.bootstrap$中的定义为:
CREATE CLUSTERC_FILE#_BLOCK#("TS#" NUMBER,"SEGFILE#"NUMBER,"SEGBLOCK#" NUMBER) PCTFREE 10 PCTUSED 40 INITRANS 2 MAXTRANS255 STORAGE ( INITIAL 24K NEXT 1024KMINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO 8 EXTENTS (FILE 1 BLOCK73)) SIZE 225可见,该簇的segment header block存放在file 1的73号block中。其中extent map的第一行指向file 1的74号block。对该block进行观察:
Bbed输出:
BBED> setblock 74 BLOCK# 74
BBED> map
File: /home/oracle/vie.pdf (1)
Block: 74 Dba:0x0040004a------------------------------------------------------------
KTB Data Block (Table/Cluster)
struct kcbh, 20 bytes a0
struct ktbbh, 72 bytes a20
struct kdbh, 14 bytes a92
struct kdbt[3], 12 bytes a106
sb2 kdbr[70] a118
ub1 freespace[5084] a258
ub1 rowdata[2846] a5342
ub4 tailchk a8188
oracle dump输出:
…………………………..省略………………….
Block header dump: 0x0040004a
Object id on Block? Y
seg/obj: 0x8 csc: 0x00.dc780c itc: 2 flg: - typ: 1 - DATA
fsl: 0 fnx: 0x0 ver: 0x01
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x0000.047.00000002 0x0040000e.0000.01 C--- 0 scn 0x0000.000000f1
0x02 0x0007.024.000018d8 0x0080190f.0c3c.05 --U- 1 fsc 0x0000.00dc780e
data_block_dump,data header at 0x1cf7365c
===============
tsiz: 0x1fa0
hsiz: 0xa6
pbl: 0x1cf7365c
bdba: 0x0040004a
76543210
flag=--------
ntab=3
nrow=70
frre=-1
fsbo=0xa6
fseo=0x1482
avsp=0x1410
tosp=0x1410
0xe:pti[0] nrow=35 offs=0
0x12:pti[1] nrow=0 offs=35
0x16:pti[2] nrow=35 offs=35
0x1a:pri[0] offs=0x1f84
0x1c:pri[1] offs=0x1f68
0x1e:pri[2] offs=0x1f4c
0x20:pri[3] offs=0x1f31
0x22:pri[4] offs=0x1f15
…………………….省略……………………….
dd输出:
00000000h: 06 A2 00 00 4A 00 40 00 FE 98 ED 00 00 00 01 04 ; .?.J.a.?....
00000010h: 6C D7 00 00 01 00 00 00 08 00 00 00 0C 78 DC 00 ; l?.........x?
00000020h: 00 00 00 00 02 00 02 00 00 00 00 00 00 00 47 00 ; ....... .....G.
00000050h: 3C 0C 05 00 01 20 00 00 0E 78 DC 00 00 03 46 00 ;<.... ...x>
00000060h: FF FF A6 00 82 14 10 14 10 14 00 00 23 00 23 00 ; ??.....#.#.
00000070h: 00 00 23 00 23 00 84 1F 68 1F 4C 1F 31 1F 15 1F ;..#.#.?h.L.1...
00000080h: F9 1E DD 1E C1 1E A5 1E 89 1E 6D 1E 52 1E 36 1E ;?????m.R.6.
00000090h: 1A 1E FE 1D E3 1D C7 1D AB 1D 8F 1D 73 1D 57 1D ; ..?????s.W.
000000a0h: 3C 1D 21 1D 05 1D E9 1C CD 1C B1 1C 96 1C 7A 1C ;<.>
000000b0h: 5E 1C 42 1C 26 1C 0B 1C EF 1B D3 1B 9F 1B 6B 1B ;^.B.&...???k.
000000c0h: 37 1B 03 1B CE 1A 9A 1A 66 1A 32 1A FE 19 CA 19 ;7...??f.2.??
000000d0h: 96 19 62 19 2E 19 FA 18 C6 18 91 18 5D 18 29 18 ;?b...???].).
000000e0h: F4 17 C0 17 82 14 58 17 24 17 F0 16 BC 16 87 16 ;???X.$.???
000000f0h: 53 16 24 16 F0 15 BB 15 87 15 53 15 1F 15 EB 14 ;S.$.???S...?
通过以下查询,确定C_FILE#_BLOCK#中存放着三个segment的数据,分别是
SYS.UET$、SYS.SEG$和C_FILE#_BLOCK#本身。
SQL> select * from sys.bootstrap$ a where a.sql_text like'%C_FILE#_BLOCK#%';
LINE# OBJ# SQL_TEXT
---------- ------------------------------------------------------------------------------------------
13 13 CREATE TABLE UET$("SEGFILE#" NUMBER NOTNULL,"SEGBLOCK#" NUMBER NOT NULL,"EXT#"
14 14 CREATE TABLE SEG$("FILE#"NUMBER NOT NULL,"BLOCK#" NUMBER NOT NULL,"TYPE#" NUMBE
8 8 CREATE CLUSTERC_FILE#_BLOCK#("TS#" NUMBER,"SEGFILE#"NUMBER,"SEGBLOCK#" NUMBER)
9 9 CREATE INDEX I_FILE#_BLOCK# ONCLUSTER C_FILE#_BLOCK# PCTFREE 10 INITRANS 2 MAXT
在bbed中观察kdbh结构体:
BBED> p kdbh
struct kdbh, 14 bytes a92
ub1 kdbhflag a92 0x00 (NONE)
b1 kdbhntab a93 3
b2 kdbhnrow a94 70
sb2 kdbhfrre a96 -1
sb2 kdbhfsbo a98 166
sb2 kdbhfseo a100 5250
b2 kdbhavsp a102 5136
b2 kdbhtosp a104 5136
kdbh结构体中的kdbhntab变量为3,与分析相符。
按前面分析,kdbt数组的长度是该块内存储的数据所属的对象的个数,每个对象占用4字节存储,该数组内存储的,实际上是每个不同对象在行偏移量列表里所对应的行的范围:
BBED> p kdbt
struct kdbt[0], 4 bytes a106
b2 kdbtoffs a106 0
b2 kdbtnrow a108 35
struct kdbt[1], 4 bytes a110
b2 kdbtoffs a110 35
b2 kdbtnrow a112 0
struct kdbt[2], 4 bytes a114
b2 kdbtoffs a114 35
b2 kdbtnrow a116 35
这里可以看到74号块内存总共放了70行数据,红色部分表示数组的第一个元素,表示第一个对象从第0行开始,共占用35行。
数组的第二个元素表示第二个对象从第35行开始,共占用了0行(其实就是SYS.UET$表,该表内没有数据)。
数组元素的第三个元素表示第三个对象从第35行开始,共占用了35行。
从sb2 kdbr[70] a118开始,存放着块内数据行的具体偏移量列表,按照上面的分析,计算kdbr结构体的偏移量为:20+24+2*24(该块内有两个itl槽)+14+3*4(该块内有来自三个对象的数据)=118,与bbed中的输出相符:
BBED> map
File: /home/oracle/vie.pdf(1)
Block: 74 Dba:0x0040004a------------------------------------------------------------
KTB Data Block(Table/Cluster) struct kcbh, 20 bytes a0
struct ktbbh, 72 bytes a20
struct kdbh, 14 bytes a92
struct kdbt[3], 12 bytes a106
sb2 kdbr[70] a118
ub1 freespace[5084] a258
ub1 rowdata[2846] a5342
ub4 tailchk a8188
进一步观察数据行内部结构。第一行偏移量为0x1f84换算为十进制为8068,如先前分析,还要加上kdbh的偏移量92,8068+92=8160。bbed中8160位置的数据如下:
00001fe0h: AC 00 03 01 00 01 00 00 40 00 4A 00 00 00 40 00; ?.. ...a.J...a.
00001ff0h: 4A 00 00 01 80 02 C1 02 03 C2 04 26 0106 FE 98 ;块最后4个字节是校验信息,红色部分就是第一行数据,逐个字节对其进行分析:
AC00 03 0100 01 00 00 40 00 4A 00 00 00 40 00 4A 00 00 01 80 02 C1 02 03 C2 04 26
第一个字节AC转换为2进制10101100,与dump中相符:
tab 0, row 0, a0x1f84
tl: 28 fb: K-H-FL-- lb: 0x0 cc: 3
curc: 1 comc: 1 pk: 0x0040004a.0 nk: 0x0040004a.0
col 0: [ 1] 80
col 1: [ 2] c1 02
col 2: [ 3] c2 04 26
这里的flag字节,比之前单个表的flag多了一位“K”,表示本行数据存放的是cluster的key。
AC 00 03 01 00 01 00 00 40 004A 00 00 00 40 00 4A 00 00 01 80 02 C1 02 03 C2 04 26
第二个字节表示该行的锁信息。
AC 00 03 01 00 01 00 00 40 00 4A 00 00 00 40 00 4A 00 00 01 8002 C1 02 03 C2 04 26第三个字节表示该行内共存放着3个字段。
AC 00 03 01 00 01 00 00 40 00 4A 0000 00 40 00 4A 00 00 01 80 02 C1 02 03 C2 04 26
从第四个字节开始的总共16个字节,记录了簇的相关信息,具体为
AC 00 03 01 00 01 00 00 40 004A 00 00 00 40 00 4A 00 00 01 80 02 C1 02 03 C2 04 26
第四、五两个字节对应dump文件中的curc的值:
tl: 28 fb: K-H-FL-- lb: 0x0 cc: 3
curc: 1 comc: 1 pk:0x0040004a.0 nk: 0x0040004a.0col 0: [ 1] 80
col 1: [ 2] c1 02
col 2: [ 3] c2 04 26
tab 0, row 1, a0x1f68
AC 00 03 01 00 01 00 00 40 00 4A 00 00 00 40 00 4A 0000 01 80 02 C1 02 03 C2 04 26第六、七两个字节对应dump文件中的comc的值:
tl: 28 fb: K-H-FL-- lb: 0x0 cc: 3curc: 1 comc: 1 pk: 0x0040004a.0 nk: 0x0040004a.0
col 0: [ 1] 80
col 1: [ 2] c1 02
col 2: [ 3] c2 04 26
tab 0, row 1, a0x1f68
AC 00 03 01 00 01 00 00 40 00 4A 00 00 00 40 004A 00 00 01 80 02 C1 02 03 C2 04 26八到十三字节记录了簇中具有该key值的前一行的存储位置,对应dump文件中的pk的值,其存储格式为,data block address.row index,表示具有这个key的值的上一行数据的存储位置,这里看到这个值是指向该行自身的,说明本行数据是簇中该key对应的第一行数据:
tl:28 fb: K-H-FL-- lb: 0x0 cc: 3
curc: 1 comc: 1 pk:0x0040004a.0 nk: 0x0040004a.0
col 0: [ 1] 80col 1: [ 2] c1 02
col 2: [ 3] c2 04 26
tab 0, row 1, a0x1f68
AC 00 03 01 00 01 00 00 40 00 4A 00 00 00 40 00 4A 0000 01 80 02 C1 02 03 C2 04 26十四到十九字节记录了簇中具有该key值的后一行的存储位置,对应dump文件中的nk的值,其存储格式为,data block address.row index,表示具有这个key的值的下一行数据的存储位置,这里看到这个值是指向该行自身的,说明本行数据是簇中该key对应的最后一行数据:
tl: 28 fb: K-H-FL-- lb:0x0 cc: 3
curc: 1 comc: 1pk: 0x0040004a.0 nk: 0x0040004a.0
col 0: [ 1] 80col 1: [ 2] c1 02
col 2: [ 3] c2 04 26
tab 0, row 1, a0x1f68
既是第一行又是最后一行表示这个键值对应的只有这一行数据。
AC 00 03 01 00 01 00 00 40 00 4A 00 00 00 40 00 4A 00 00 0180 02 C1 02 03 C2 04 26下一个字节01表示第一个字段占一个字节存储。
AC 00 03 01 00 01 00 00 40 00 4A 00 00 00 40 00 4A 00 00 01 8002 C1 02 03 C2 04 2680是第一个字段的值0的oracle内部表示方法。
AC 00 03 01 00 01 00 00 40 00 4A 00 00 00 40 00 4A 00 00 01 80 02C1 02 03 C2 04 26下一个字节02表示第二个字段占两个字节存储。
AC 00 03 01 00 01 00 00 40 00 4A 00 00 00 40 00 4A 00 00 01 80 02 C102 03 C2 04 26下两个字节C1 02是数字1的oracle内部表示方法。
AC 00 03 01 00 01 00 00 40 00 4A 00 00 00 40 00 4A 00 00 01 80 02 C102 03 C2 04 26下一个字节的03表示第三个字段占三个字节存储。
AC 00 03 01 00 01 00 00 40 00 4A 00 00 00 40 00 4A 00 00 01 80 02 C102 03 C2 04 26最后三个字节C2 04 26是数字337的oracle内部表示方法。
至此,单表及簇表通过segment header块定为数据行的大体流程已经清晰,总结如下。
对于单表:
1、 在segment header block偏移量96的位置找到ktemh结构体的next_ktemh变量,该变量指向segment的下一个extent map。如果该变量的值为0x00000000,表示该segment的所有数据都存储在一个segment中。
2、 在segment header block偏移量108的位置找到ktetb数组,该数组中每个节点占8字节,前4字节为extent首地址,后4字节为extent内块的个数。
3、 通过extent map找到具体存储数据的块。
4、 在数据块内找到kdbh数据结构,其偏移量为:20+24+ktbbh. Ktbbhict(块内偏移量36位置,长度两字节)*24。
5、 找到kdbr数组,其偏移量为:kdbh的偏移量+14(kdbh结构体的长度)+kdbh结构体中kdbhntab变量的值*4(每个表占4字节)。
6、 取出kdbr中行的偏移量,将该值加上kdbh的偏移量值,得到行物理偏移量。
7、 根据行物理偏移量,找到行数据起始位置,并取出其首字节flag。根据块的flag判断行头的不同长度。如,普通无行链接数据行,flag为2C对应为二进制00101100 --H-FL—则行内数据位于行头偏移3字节的位置。簇且无行链接数据行,flag为AC对应二进制10101100 K-H-FL—则行内数据位于行头偏移19字节的位置。
8、 在行头第三个字段,取出行内字段个数。
9、 在行头后找到首个字段的长度,并按该长度取出其后的字段值。
10、 按步骤9递归取出行内全部字段的值。
下一步就是要将取出的二进制数据转换为明文。