一次無備份、非歸檔資料庫斷電恢復的全過程

blue_prince發表於2005-11-02
環境:Windows 2000 Advanced Server sp4+Oracle 9206

現象描述:客戶資料庫機房在清理過程中,清潔人員不小心將伺服器後面的電源線直接拔掉,導致例項斷電,資料庫無法啟動。資料庫執行在非歸檔模式下,沒有備份,只有前一天晚上的全庫匯出檔案。資料庫重新啟動以後,資料庫無法開啟,用SQLPLUS連線,無論如何都無法登入進去,報錯如下:
[@more@]SQL> conn/as sysdba
ERROR:
ORA-01041: internal error. hostdef extension doesn't exist??

SQL> conn sys/aa as sysdba
ERROR:
ORA-03113: end-of-file on communication channel

解決問題的第一步就是查詢alert log,相應內容如下:
程式碼:

Mon Aug 01 22
:03:52 2005
alter database mount exclusive
Mon Aug 01 22
:03:
56 2005
Successful mount of redo thread 1
,
with mount id 1487340872
Mon Aug 01 22
:03:
56 2005
Database mounted in Exclusive Mode
. Completed: alter database mount exclusive
Mon Aug 01 22
:03:
56 2005
alter database open
Mon Aug 01 22
:03:
56 2005
Beginning crash recovery of 1 threads
Mon Aug 01 22
:03:
56 2005
Started redo scan
Mon Aug 01 22
:03:
56 2005
Completed redo scan
17289 redo blocks read
,
394 data blocks need recovery
Mon Aug 01 22
:03:
56 2005
Started recovery at
Thread 1
: logseq 52, block 92832,
scn 0.0
Mon Aug 01 22
:03:
56 2005
Recovery of Online Redo Log
:
Thread 1 Group 1 Seq 52 Reading mem 0
Mem
# 0 errs 0: E:/ORACLE/ORADATA/RMADB/REDO01.LOG *** Corrupt block relative dba: 0x02c1f8c8 (file 11, block 129224) Fractured block found during crash/instance recovery
Data in bad block
-
type: 6 format: 2 rdba:
0x02c1f8c8
last change scn
: 0x0000.0017d929 seq: 0x1 flg:
0x06
consistency value in tail
:
0xc0250601
check value in block header
: 0x54b9, computed block checksum:
0x190c
spare1
: 0x0, spare2: 0x0, spare3:
0x0 *** Reread of rdba: 0x02c1f8c8 (file 11, block 129224) found same corrupted data *** Corrupt block relative dba: 0x008008f9 (file 2, block 2297) Fractured block found during crash/instance recovery
Data in bad block
-
type: 2 format: 2 rdba:
0x008008f9
last change scn
: 0x0000.0017f574 seq: 0x2 flg:
0x04
consistency value in tail
:
0x1c9c0208
check value in block header
: 0xaede, computed block checksum:
0xd131
spare1
: 0x0, spare2: 0x0, spare3:
0x0 *** Reread of rdba: 0x008008f9 (file 2, block 2297) found same corrupted data *** Corrupt block relative dba: 0x02c0d2a8 (file 11, block 53928) Fractured block found during crash/instance recovery
Data in bad block
-
type: 6 format: 2 rdba:
0x02c0d2a8
last change scn
: 0x0000.0017fbcb seq: 0x1 flg:
0x06
consistency value in tail
:
0xd0270601
check value in block header
: 0x9225, computed block checksum:
0x2bec
spare1
: 0x0, spare2: 0x0, spare3:
0x0 *** Reread of rdba: 0x02c0d2a8 (file 11, block 53928) found same corrupted data *** Corrupt block relative dba: 0x02c09248 (file 11, block 37448) Fractured block found during crash/instance recovery
Data in bad block
-
type: 6 format: 2 rdba:
0x02c09248
last change scn
: 0x0000.0017fa10 seq: 0x1 flg:
0x06
consistency value in tail
:
0xf7ec0601
check value in block header
: 0xd53f, computed block checksum:
0xdfc
spare1
: 0x0, spare2: 0x0, spare3:
0x0 *** Reread of rdba: 0x02c09248 (file 11, block 37448) found same corrupted data *** Corrupt block relative dba: 0x028205c3 (file 10, block 132547) Fractured block found during crash/instance recovery
Data in bad block
-
type: 6 format: 2 rdba:
0x028205c3
last change scn
: 0x0000.0017e7ca seq: 0x1 flg:
0x06
consistency value in tail
:
0xf0270601
check value in block header
: 0x3e5e, computed block checksum:
0x17ed
spare1
: 0x0, spare2: 0x0, spare3:
0x0 *** Reread of rdba: 0x028205c3 (file 10, block 132547) found same corrupted data *** Corrupt block relative dba: 0x00800099 (file 2, block 153) Fractured block found during crash/instance recovery
Data in bad block
-
type: 38 format: 2 rdba:
0x00800099
last change scn
: 0x0000.0017feda seq: 0x1 flg:
0x04
consistency value in tail
:
0xe6532601
check value in block header
: 0x2901, computed block checksum:
0x2c6
spare1
: 0x0, spare2: 0x0, spare3:
0x0 *** Reread of rdba: 0x00800099 (file 2, block 153) found same corrupted data *** Corrupt block relative dba: 0x00800419 (file 2, block 1049) Fractured block found during crash/instance recovery
Data in bad block
-
type: 2 format: 2 rdba:
0x00800419
last change scn
: 0x0000.0017e682 seq: 0x3 flg:
0x04
consistency value in tail
:
0x99d90208
check value in block header
: 0x1f63, computed block checksum:
0x637
spare1
: 0x0, spare2: 0x0, spare3:
0x0 *** Reread of rdba: 0x00800419 (file 2, block 1049) found same corrupted data *** Corrupt block relative dba: 0x00800079 (file 2, block 121) Fractured block found during crash/instance recovery
Data in bad block
-
type: 38 format: 2 rdba:
0x00800079
last change scn
: 0x0000.0017e683 seq: 0x1 flg:
0x04
consistency value in tail
:
0xfc202601
check value in block header
: 0xa5d7, computed block checksum:
0x9c09
spare1
: 0x0, spare2: 0x0, spare3:
0x0 *** Reread of rdba: 0x00800079 (file 2, block 121) found same corrupted data *** Corrupt block relative dba: 0x00800009 (file 2, block 9) Fractured block found during crash/instance recovery
Data in bad block
-
type: 38 format: 2 rdba:
0x00800009
last change scn
: 0x0000.0017ce51 seq: 0x1 flg:
0x04
consistency value in tail
:
0xe63a2601
check value in block header
: 0x28a7, computed block checksum:
0x2f8c
spare1
: 0x0, spare2: 0x0, spare3:
0x0 *** Reread of rdba: 0x00800009 (file 2, block 9) found same corrupted data
Mon Aug 01 22
:03:
58 2005
Errors in file e
:/oracle/admin/rmadb/udumps/rmadb_ora_1664.trc
: ORA-00600: ??????, ??: [6101], [0], [15], [0], [], [], [], [] Mon Aug 01 22:03:59 2005
Errors in file e
:/oracle/admin/rmadb/udump/rmadb_ora_1664.trc
: ORA-01578: ORACLE ?????? (???? 10, ???? 41861) ORA-01110: ??? 10: 'D:/DATA/BASERINDEX_1.DAT' ORA-10564: tablespace RINDEX
ORA
-01110: ??? 10:
'D:/DATA/BASERINDEX_1.DAT' ORA-10561: block type 'TRANSACTION MANAGED INDEX BLOCK', data object# 29492 ORA-00600: ??????, ??: [6101], [0], [15], [0], [], [], [], []

...




查詢Metalink中關於ora-600[6101]的錯誤解釋,結合alert log裡面的資訊,我們可以知道由於斷電導致資料庫UNDO表空間和應用索引表空間RINDEX對應的兩個資料檔案損毀,產生壞塊,因此資料庫無法開啟。值得慶幸的是,損毀的表空間不是應用資料表空間,這樣至少業務資料不會有多大丟失。瞭解了情況以後,大抵對策也就出來了,將損毀的索引表空間對應兩個資料檔案offline drop,然後再透過新增隱藏引數的辦法使資料庫跳過回滾段的檢查來不一致開啟資料庫。開啟資料庫後,再做一個全庫的匯出,然後重建資料庫,匯入資料即可。


可是這時候SQLPLUS卻是始終無法登入,無論怎樣連線,都是持續地報ORA-01041和ORA-03113這兩個錯誤。嘗試重配監聽,透過網路連線,無法登入;用RMAN連線,還是無法登入,報的錯一模一樣。查詢Google和Metalink,找不到有用的資訊。如果連SQLPLUS都無法登入,那麼恢復根本無從談起。這時候便從各方面尋找原因,本來是想用oradim重新編輯Oracle服務,使得Windows服務啟動時Instance不直接mount資料庫和開啟資料庫。但是轉而一想,目前Oracle服務還是可以自動mount資料庫,只是由於資料壞塊的產生無法開啟資料庫罷了,況且這時候只是SQLPLUS無法登入,如果手工編輯服務,資料庫連mount都無法mount的話,SQLPLUS又是無法登入,那麼更加難以著手進行恢復了。到這個時候只能懷疑是否是Oracle本身的問題,SQLPLUS程式因為斷電的原因發生錯誤?

想到這一點以後,便保護好現場,重新安裝Oracle並手工建立服務,再嘗試進行恢復。於是便又開始了重新安裝Oracle及打Patch的過程。當安裝好Oracle以後,利用oradim手工編輯Oracle服務,並利用orapwd建立好相應的密碼檔案後,再進一步嘗試恢復。這次Oracle服務啟動以後,不會再啟動Instance了,馬上利用SQLPLUS嘗試登入,乖乖,終於登入進去了:

SQL> conn/as sysdba
Connected to an idle instance.

馬上嘗試著啟動Insance,並mount資料庫,都順利完成了:

SQL> startup nomount
ORACLE instance started.

Total System Global Area 68229684 bytes
Fixed Size 453172 bytes
Variable Size 41943040 bytes
Database Buffers 25165824 bytes
Redo Buffers 667648 bytes

SQL> alter database mount;

Database altered.

當嘗試開啟資料庫時,SQLPLUS馬上斷開連線,並重新報ORA-01041的錯誤:

SQL> alter database open;
ERROR:
ORA-01041: internal error. hostdef extension doesn't exist?

至此,大抵明白了剛開始時SQLPLUS為何無法登入的原因:Oracle服務成功mount資料庫後,會嘗試開啟資料庫,由於Ora-600的存在,這時候無論透過何種方式都是無法連線到資料庫的,並且會報ORA-01041的錯誤。清楚這一點以後,我們再次嘗試進一步的恢復,由於SQLPLUS無法連線,手工將Oracle服務關閉並再次開啟,這時候SQLPLUS又可以登入了,於是mount資料庫,建立pfile檔案,準備新增隱藏引數:

SQL> create pfile='d:/init.ora' from spfile;

File created.

開啟d:/init.ora檔案,修改undo_management為manual,將在在裡面新增如下一行隱藏引數,以便資料庫開啟時跳過已損壞的回滾段的檢查:

*._corrupted_rollback_segments=(“_SYSSMU1$”,”_SYSSMU2$”,”_SYSSMU3$”,”_SYSSMU3$”,”_SYSSMU4$”,”_SYSSMU5$”,” _SYSSMU6$”,”_SYSSMU7$”,” _SYSSMU8$”,”_SYSSMU9$”,”_SYSSMU10$”);

這裡就又帶來一個問題,自從9i Undo管理方式採用自動管理以後,我們根本無法得知Oracle內部建立了幾個回滾段以及回滾段相應的名稱,資料庫在mount狀態下,我們也無法透過資料字典來查詢回滾段的相應資訊,那麼這些回滾段的名稱如何得來?如果建庫以來的alert log都存在的話,那麼我們可以結合建立資料庫時的alert log內容以及最後一次成功開啟資料庫後的alert log內容來猜測資料庫中回滾段的數目及名稱。我們首先來檢視一個alert log裡面記錄的建立資料庫時對應建立UNDO表空間及Undo Segment的名稱的例子:

程式碼:

Tue May 31 22
:42:26 2005
CREATE UNDO TABLESPACE UNDO DATAFILE
'd:oracleoradatademoundo01.dbf' size 300M

Tue May 31 22
:42:28 2005
Created Undo Segment _SYSSMU1
$ Created Undo Segment _SYSSMU2$ Created Undo Segment _SYSSMU3$ Created Undo Segment _SYSSMU4$ Created Undo Segment _SYSSMU5$ Created Undo Segment _SYSSMU6$ Created Undo Segment _SYSSMU7$ Created Undo Segment _SYSSMU8$ Created Undo Segment _SYSSMU9$ Created Undo Segment _SYSSMU10$
...



通常情況下,Oralce初始建庫時都是建立10個回滾段,名稱分別命名為“_SYSSMU1$”、“_SYSSMU2$”……“_SYSSMU10$”;在這裡我們不難看出Undo Segment的命名規範,為“_SYSSMUn$”,其中n為Undo Segment對應的數目編號。結合最後一次資料庫成功啟動後的alert log裡面Undo Segment的相應資訊:

程式碼:

Sat Jul 30 10
:35:16 2005
ARC0
: Media recovery disabled
Sat Jul 30 10
:35:17 2005
Undo Segment 1 Onlined
Undo Segment 2 Onlined
Undo Segment 3 Onlined
Undo Segment 4 Onlined
Undo Segment 5 Onlined
Undo Segment 6 Onlined
Undo Segment 7 Onlined
Undo Segment 8 Onlined
Undo Segment 9 Onlined
Undo Segment 10 Onlined
Successfully onlined Undo Tablespace 1.
Sat Jul 30 10
:35:17 2005
...



我們就可以得知資料庫大概有幾個Undo Segment以及他們對應的名稱。事實上,資料庫在執行過程中可能也會建立相應的Undo Segment,這些我們都可以透過alert log裡面記錄的內容進行補充新增,這樣我們就可以知道Undo Segment的相應資訊了。

新增隱藏引數後,關閉資料庫服務,以剛建立的pfile進行啟動:

SQL> startup nomount pfile='d:/init.ora'
ORACLE instance started.

Total System Global Area 68229684 bytes
Fixed Size 453172 bytes
Variable Size 41943040 bytes
Database Buffers 25165824 bytes
Redo Buffers 667648 bytes

SQL> alter database mount;

Database altered.

Mount完資料庫後,將損壞的索引表空間對應的資料檔案offline drop掉:

SQL> alter database datafile 10 offline drop;

Database altered.

SQL> alter database datafile 11 offline drop;

Database altered.

接下便是最關鍵的一步,嘗試開啟資料庫:

SQL> alter database open;

Database altered.

乖乖,資料庫終於成功開啟了,幾個小時的折騰終於有了結果。接下來的第一步便是馬上做一個全庫匯出。事實上當時在這個損毀的資料庫上匯出時應用資料表空間還是存在壞塊的,一些表是無法成功匯出的。但是萬幸的是,這些表都是一些程式碼表,涉及到業務交易資料的幾張重要的表都成功匯出了。匯出完以後,重建資料庫,匯入剛才全庫匯出的資料。結合前天晚上的全庫匯出檔案及上面匯出的日誌,將損壞的資料表也完整地匯入到新建立的資料庫中,這樣實現了資料的零丟失。至此,整個資料庫的恢復順利完成。

後記:
當時在恢復過程中為了保險起見,沒有采用一些更簡便的方法。事實上從後面的恢復過程中我們不難看出,最簡便保險的方法就是手工編輯Oracle服務,便得Oracle服務不會自動啟動資料庫,這樣SQLPLUS就可以登入,也就能進行後面的恢復步驟了。當時經與同事討論以及後面的論壇交流後,發生ORA-01041這樣的情況,事實上只要在Windows的工作管理員中將oracle.exe的程式kill掉,那麼再次登入SQLPLUS時就可以登入了,恢復過程也就大同小異了。當時之所以選擇案例中解決的辦法,主要是由於前面所述兩種方法在當時看來都不是十分保險,因為服務都已經成功mount資料庫了,但是就是SQLPLUS無法登入。如果按上面的方法進行解決,SQLPLUS還是無法登入的話,那麼根本無從談起恢復,尤其像後面的將oracle.exe程式結束掉,又怕將本來完好的控制檔案給損毀掉,這時SQLPLUS又無法登入,想重新建立都無法建立。基於這點考慮,最後才選擇了案例中的恢復辦法。這個案例的重點是解決SQLPLUS無法登入的問題,上面的解決辦法及思路可供大家日後測試和恢復時作為參考。這裡需要再次強調的是生產資料庫一定要做好備份的工作,否則發生異常的話,有些情況下是根本無法完好恢復的。

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

相關文章