Oracle資料庫特種恢復技術(四)--實驗篇

jinqibingl發表於2012-10-04

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


         原計劃中沒有這一章節,但是朋友建議我將整個過程的串聯獨立出來,因此這一部分用一個實際的例子把前三篇的內容做一個串聯。
         本次試驗使用的資料庫版本為11.2.0.2.0且打了最新的psu。之所以使用11g版本的資料庫,是因為之前的章節都是在10g的基礎上進行試驗的,這裡使用11g驗證一下之前的分析結果在不同版本平臺的通用性。

create table XH_TEST

(

  DUMMY VARCHAR2(1),

  NUM   NUMBER,

  VCHAR VARCHAR2(4000),

  DAT   DATE

)

tablespace SYSTEM

  pctfree 10

  pctused 40

  initrans 1

  maxtrans 255


      建立試驗用的表,為方便起見表空間選擇system,這樣整個試驗只用一個資料檔案就行了。
      關閉資料庫,並假設資料庫由於故障已經不能啟動,現在要在不啟動資料庫的情況下僅透過表名稱“XH_TEST”恢復該表,步驟如下
首先透過控制檔案查詢資料檔案的物理路徑,在作業系統中執行:

[root@ABnet-db~]# cd /

[root@ABnet-db/]# find . -name *.ctl

      因為11g透過dbca建立的庫,預設是沒有pfile的,因此透過副檔名搜尋oracle控制檔案。這裡需要注意的是,在安裝、部署一個系統時,無論是資料庫還是應用系統,最好都按照通用慣例來命名各種檔案、變數等資源,這樣能在之後的工作中帶來極大的便利。
      將控制檔案下載到本地進行分析。這裡有一個問題,其實這整篇文章中的相關技術在一年前就都已經摸索清楚了,但是卻一直沒有找到分析oracle控制檔案結構的方法或文件,國外比較權威的社群中也只能找到控制檔案頭的相關結構介紹,現在只能確定控制檔案也是採用資料塊的格式進行儲存的,因此目前只能採用人工的方式從重獲取資訊,如果哪位能夠不吝提供相關幫助的話,就萬分感激了。
      使用ue開啟控制檔案,搜尋system關鍵字,之所以搜尋system而不是system01.dbf是因為asm命名的檔案中也帶有表空間關鍵字,但不帶序號。在實驗用的兩個庫中,10g的控制檔案中system表空間的第一個檔案的完整檔名存放在0x7cc66的位置,在11g的控制檔案中該檔名存放在0x7528a的位置。找到該位置後,向前倒數8個位元組的位置的01判斷為是該檔案的絕對檔案號,再向前兩位元組的04判斷為檔案型別標識,這就意味著絕對檔案號佔用了兩個位元組儲存,其最大值為0xffff與oracle聲稱的最大支援檔案數量65534基本相符。從這裡也可以領會到另一個事實,即,資料庫中一些指標的上限,如最大表數量、最大欄位數量、最大檔案數量、最大表空間數量等等,這些指標的上限其實都是由儲存該指標的某個變數或欄位的最大長度決定的。
         確定系統表空間第一檔案的物理路徑後深入觀察。這裡我編寫了一段java程式,用以從指定緩衝區的指定偏移量讀出指定數量的位元組,並以指定格式返回,也可以使用其他方法做轉換。
按前面幾部分的分析,首先從該檔案的檔案頭偏移8192+96=8288位置讀取4個位元組的root dba的值:08 02 40 00,進行位元組序轉換並轉換為二進位制並補齊32位為:00000000010000000000001000001000,按dba格式轉換為1號檔案520號資料塊。
進入520號資料塊,

1、  讀出offset 96位置的4個位元組的ktemh.next_ktemh變數的值:00 00 0000。(下一個extent map塊的地址)

2、  讀出offset 92位置的4個位元組的ktemh. count_ktemh變數的值:01 00 0000。(當前segment header block中的extent map的行數)

3、  讀出offset 108位置的8個位元組:09 02 4000 07 00 00 00,將前4個位元組進行位元組序轉換並轉換為二進位制並補齊32位為:00000000010000000000001000001001,按dba格式轉換為1號檔案521號資料塊。將後4個位元組進行位元組序轉換並轉換為十進位制為:7。

從以上結果判斷,sys.bootstrap$表的全部資料儲存在1號檔案521號塊開始的連續7個資料塊中。
1、  進入521號資料塊,
2、讀出offset 36位置的1個位元組的ktbbhict變數的值:01(注1:這裡有bbed的一個bug)。
3、計算kdbh結構體的偏移量為:20+24+1*24=68。
4、讀出offset 68+1位置的一個位元組的kdbhntab­­變數的值:01,該值表示塊記憶體儲的資料行屬於一個表。
5、讀出offset 68+2位置的兩個位元組的kdbhnrow變數的值:18 00,該值表示塊內共儲存24行資料。
6、  計算kdbr陣列的偏移量為:68+14+1*4=86。
7、讀出offset 86位置的2*24=48位元組的kdbr陣列,並按照每兩個位元組一個元素分割:

A3 1F, 1A 1F, 95 1D, CD 1C, 4E 1B, 7A 1A,AD 19, 49 17,

7B 16, B3 15, D6 14, 0A 14, EF 12, 05 12,0E 11, 38 0F,

68 0E, 91 0D, 79 0C, 69 09, 9C 08, 5E 06,8D 05, C6 04

      將每個元素進行位元組序轉換後轉換為10進位制:8099,7962,7573。。。。省略。。。將每個行偏移量加kdbh結構體的偏移量得出行資料實際物理位置。

9、讀出一行資料:2C 01 03 033E 64 66 03 3E 64 66 09 38 2E 30 2E 30 2E 30 2E 30,從第四位元組擷取三個位元組3E64 66,轉換為真實數值為:-(101-100)*100^(62-62)=-1。最後9位元組:38 2E 30 2E 30 2E 30 2E 30轉換為字串:“8.0.0.0.0”。

10、如果當前行不是第24行,則重複執行步驟8。
11、如果當前塊不是521號塊後的第七個塊,則重複執行步驟1。

至此,sys.bootstrap$表的資料已經得以恢復,下一步要透過該表定位並恢復資料字典表。要透過資料字典定位表的物理位置,實際上類似於執行以下sql語句:select a.file#,a.block# from sys.tab$ a,sys.obj$ b where a.obj# =b.obj# and b.name = '*****';因此只要恢復sys.tab$、sys.obj$兩個表的資料就能定位任意表的物理位置。

從已經恢復出的sys.bootstrap$表的資料中找到sys.tab$、sys.obj$兩表的定義可知,sys.obj$儲存在FILE 1BLOCK 240位置,sys.tab$儲存在C_OBJ#簇中,C_OBJ#簇儲存在FILE 1 BLOCK 296位置。恢復sys.obj$的過程與本章節前面恢復sys.bootstrap$表的過程完全相同,不再贅述。sys.tab$恢復過程如下:

1、  進入1號檔案296號塊。

2、  讀出offset 96位置的4個位元組的ktemh.next_ktemh變數的值:00 00 0000。

3、  讀出offset 92位置的4個位元組的ktemh.count_ktemh變數的值: 11 0000 00。

4、  讀出offset 108位置的8*17個位元組,逐個轉換為extent首地址。
其中第一個extent位於1號檔案145號資料塊:
1、  進入145號塊。

2、  讀出offset 36位置的一個位元組的ktbbh.Ktbbhict的值:02。(表示存在兩個itl槽)

3、  計算kdbh結構體偏移量為20+24+2*24=92。

4、  讀出offset:kdbh+1位置的一個位元組的kdbh. Kdbhntab的值:06。(表示塊內資料屬於6個物件)

5、  讀出offset:kdbh+14位置的kdbt陣列,該陣列保函6個元素(表示六個表),每個元素長度為4位元組。

6、  讀出offset:kdbh+14(kdbh的長度)+24(kdbt陣列的長度)位置的kdbr陣列。

7、  按kdbr陣列中記錄的行偏移量加上kdbh的偏移量92,逐行讀取行資料。
8、  讀出一行資料舉例舉例:
6C 00 14 07 02 C1 06 02 C1 07 02 C1 17 01 80 06
42 4C 4F 43 4B 23 02 C1 03 02 C1 17 01 80 FF FF
02 C1 02 FF FF 02 C1 06 01 80 01 80 01 80 01 80
01 80 0180
第一個位元組flag的值6C轉換為二進位制01101100,表示-CH-FL--,說明該行市一個簇成員物件資料行,並且head piece、first piece、last piece都儲存在本行沒有行連結現象。
第二個位元組00表示行鎖資訊。
第三個位元組14表示改行儲存20個欄位。
第四個位元組07表示該行對應的clusterkey的index資訊,這裡的07表示該行資料和本塊內的key行的第7行對應。
第五個位元組的02表示第一個欄位佔兩個位元組儲存。
第六、七兩個位元組C1 06是第一個欄位的值5。
第八個位元組的02表示第二個欄位佔兩個位元組儲存。
第九、十兩個位元組C1 07是第二個欄位的值6。
第十一個位元組的02表示第三個欄位佔兩個位元組儲存。
第十二、十三兩個位元組C117是第三個欄位的值22。
第十四個位元組的01表示第四個欄位佔一個位元組儲存。
第十五個位元組的80是第四個欄位的值0。
第十六個位元組的06表示第五個欄位佔六個位元組儲存。
第十七至二十二位元組的424C 4F 43 4B 23是第五個欄位的值“BLOCK#”。
第二十三位元組的02表示第六個欄位佔兩個位元組儲存。
第二十四、二十五位元組的C1 03是第六個欄位的值2。
第二十六位元組的02表示第七個欄位佔兩個位元組儲存。
第二十七、二十八兩個位元組C117是第七個欄位的值22。
第二十九位元組的01表示第八個欄位佔一個位元組儲存。
第三十位元組的80是第八個欄位的值0。
第三十一、三十二位元組的FFFF表示第九、十兩個欄位為null。
第三十三位元組的02表示第十一個欄位佔兩個位元組儲存。
第三十四、三十五兩個位元組C102是第十一個欄位的值1。
第三十六、三十七位元組的FFFF表示第十二、十三欄位為null。
第三十八個位元組的02表示第十四個欄位佔兩個位元組儲存。
第三十九、四十兩個位元組C106是第十四個欄位的值5。
其後的十二個位元組01 8001 80 01 80 01 80 01 80 01 80表示後六個欄位的值全部為0。         (註釋1)      
         到這裡,sys.c_obj$簇以及其所保函的sys.tab$表已經恢復,sys.obj$表也已經恢復,透過這兩個表的資料,已經可以定位XH_TEST表的header block所在的檔案號以及位置,之後的工作就是對XH_TEST表進行恢復,恢復過程與恢復sys.obj$表的過程完全相同,不再贅述。
         至此,已經成功的在脫離oracle資料庫軟體的情況下恢復了XH_TEST表的資料,下一步要進一步考慮資料完整性的保障,例如,表有未提交事務時前滾、回滾的完成等細節。
註釋1:在這裡我有一個問題一直沒有找到結果,就是:一個簇中具有相同簇鍵的不同表的資料行是儲存在同一個資料塊裡的,比如剛剛分析的145號資料塊保函了6個表的資料,那麼oracle是如何分辨哪一行是屬於哪個表的?我一開始分析肯定是記錄在某個資料字典裡的,但是一直沒有找到,而且如果是放在資料字典裡的,那麼這個資料字典的載入順序必然要先於sys. tab$因為sys.tab$是sys. bootstrap$裡最靠前載入的一個表物件,在它前面載入的都是簇、索引、回滾段等,但是sys.tab$前面沒有和簇、表相關的字典載入了。如果哪位能在這個問題上指點一二,一定感激不盡。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/9606200/viewspace-745680/,如需轉載,請註明出處,否則將追究法律責任。

相關文章