oracle資料庫特種恢復技術(二)—塊內篇
oracle資料庫特種恢復技術(二)—塊內篇
oracle資料庫特種恢復技術(二)—塊內篇
作者:謝浩
Oracle資料庫特種恢復技術—原理篇連結:http://www.itpub.net/thread-1507760-1-1.html
oracle資料庫特種恢復技術—塊內篇連結:http://www.itpub.net/thread-1507766-1-1.html
oracle資料庫特種恢復技術—轉換篇連結:http://www.itpub.net/thread-1507774-1-1.html
繼續上一次的內容。
明確了大體思路後,需要進入資料檔案內部解析出資料行。結合使用bbed、dump、ue進行觀察。分析oracle塊內物理結構時可採用的方法是:首先在dump檔案中找到所關心的變數,然後在dd輸出中對照查詢該變數的值並記錄偏移量,最後在bbed輸出中檢視該偏移量對應的資料結構進行驗證。Oracle資料庫中的V$TYPE_SIZE檢視記錄了塊內各個變數及結構體的長度和簡單描述,熟悉後可以簡單的透過對變數名縮寫的估計找到對應的dump檔案中的變數。
首先觀察資料庫1號檔案的377資料塊,也就是sys.bootstrap$表的segment head block。
Bbed輸出:
BBED> setblock 377
BLOCK# 377BBED> 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: 7last 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
UnlockedMap 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 a96ub4 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# 378BBED> 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 ffs=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# 74BBED> 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 ffs=0
0x12:pti[1] nrow=0 offs=35
0x16:pti[2] nrow=35 ffs=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 a0struct 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個位元組是校驗資訊,紅色部分就是第一行資料,逐個位元組對其進行分析:AC 00 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
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.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
第六、七兩個位元組對應dump檔案中的comc的值: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 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] 80
col 1: [ 2] c1 02col 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] 80
col 1: [ 2] c1 02col 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 26
80是第一個欄位的值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遞迴取出行內全部欄位的值。
下一步就是要將取出的二進位制資料轉換為明文。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/9606200/viewspace-745678/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- oracle資料庫特種恢復技術(五)--redo篇Oracle資料庫
- Oracle資料庫特種恢復技術(一)—原理篇Oracle資料庫
- oracle資料庫特種恢復技術(三)—轉換篇Oracle資料庫
- Oracle資料庫特種恢復技術(四)--實驗篇Oracle資料庫
- ORACLE資料庫恢復技術Oracle資料庫
- 恢復資料,資料塊恢復
- oracle asm 資料塊重構恢復OracleASM
- rman 恢復資料塊
- rman恢復資料塊
- Oracle-誤刪資料恢復(短期內)Oracle資料恢復
- 資料庫備份與恢復技術資料庫
- 資料塊恢復例項
- ORACLE資料恢復Oracle資料恢復
- 【資料庫資料恢復】Oracle資料庫檔案出現壞塊報錯的資料恢復案例資料庫資料恢復Oracle
- Oracle資料壞塊簡介及其恢復(dbv、BMR)Oracle
- 轉載:Oracle資料塊損壞恢復總結Oracle
- Oracle可恢復空間分配技術Oracle
- SQL Server資料庫多資料檔案恢復技術SQLServer資料庫
- RMAN blockrecover命令恢復資料塊BloC
- 基於資料塊的恢復
- oracle資料庫備份和恢復的內容Oracle資料庫
- ORACLE-資料恢復Oracle資料恢復
- bbed_recover:恢復資料塊資料庫資料庫
- Oracle中truncate table後的資料恢復(Oracle資料恢復工具-ODU)Oracle資料恢復
- 資料庫資料恢復-ORACLE資料庫的常見故障&各種故障下的資料恢復可能性資料庫資料恢復Oracle
- 資料庫恢復子系統的常見技術和方案對比(二)資料庫
- 【管理篇備份恢復】rman恢復測試(二) 控制檔案恢復(二)
- 【資料庫資料恢復】如何恢復Oracle資料庫truncate表的資料資料庫資料恢復Oracle
- Oracle資料庫備份與恢復的三種方法Oracle資料庫
- --bbed_recover:恢復資料塊資料庫(mybbed)資料庫
- bbed_recover:恢復資料塊資料庫(續)資料庫
- Oracle恢復誤刪資料Oracle
- Oracle資料恢復專題Oracle資料恢復
- oracle資料恢復還原Oracle資料恢復
- Oracle rman 各種恢復Oracle
- 【資料庫資料恢復】Oracle資料庫誤truncate table的資料恢復案例資料庫資料恢復Oracle
- 【資料庫資料恢復】oracle資料庫誤truncate table怎麼恢復資料?資料庫資料恢復Oracle
- 【資料庫資料恢復】誤truncate table的Oracle資料庫資料恢復方案資料庫資料恢復Oracle