Oracle-無備份情況下,如何手動恢復控制檔案

monkey6發表於2024-04-27

1.測試場景

本文主要模擬在控制檔案沒有備份的情況下丟失,如何根據已有的引數檔案、資料檔案、線上日誌資訊去手動生成控制檔案。

2.測試環境

Oracle單例項:11.2.0.4

資料檔案目錄:/u01/app/oracle/oradata/HJDB/datafile

線上日誌目錄:/u01/app/oracle/oradata/HJDB/onlinelog

3.建立檔案所需要的資訊和選項

以下這些選項跟資料庫的引數檔案、資料檔案、線上日誌沒有強關聯性,可以自行根據環境需要進行設定。

  1. reuse選項

    指定是否覆蓋已有的控制檔案。不指定,如果目錄下有相同的控制檔案,會建立失敗報錯,指定即直接覆蓋。

    ORA-00200: control file could not be created
    ORA-00202: control file:
    '/u01/app/oracle/oradata/HJDB/controlfile/o1_mf_lyhr3fcp_.ctl'
    ORA-27038: created file already exists
    
  2. NORESETLOGS選項

    如果資料庫是完整的恢復,包含完整的線上日誌,可以選擇NORESETLOGS方式建立。

    如果資料庫是不完整的恢復,需要選擇RESETLOGS方式建立。

  3. ORCE LOGGING選項

    資料庫是否開啟force logging 。

  4. ARCHIVELOG/NOARCHIVELOG選項

    資料庫歸檔模式。

  5. MAXLOGFILES選項

    設定建立的控制檔案的日誌組數量,要大於當前的線上日誌組group的大小,比如日誌組有3組,分別為11,12,13,則MAXLOGFILES設定要大於13。

  6. MAXLOGMEMBERS選項

    設定建立的控制檔案每個日誌組的成員最大數量,通常為1-2。

  7. MAXDATAFILES選項

    設定建立的控制檔案的最大資料檔案數量,大於當前的資料檔案數量,不超過db_files即可。

  8. MAXINSTANCES選項

    設定可以同時掛載和開啟資料庫的最大例項數。

  9. MAXLOGHISTORY選項

    設定控制檔案記錄的歸檔日誌參考數量。

    這裡我們按以下配置進行設定,資料庫名DB_NAME暫時不填寫。

    CREATE CONTROLFILE REUSE DATABASE "XXXX" NORESETLOGS FORCE LOGGING ARCHIVELOG
        MAXLOGFILES 20
        MAXLOGMEMBERS 2
        MAXDATAFILES 200
        MAXINSTANCES 2
        MAXLOGHISTORY 1024
    

4.獲取相關資訊

4.1.DB_NAME資訊獲取

4.1.1.alert日誌的啟動資訊獲取

$ cat alert_hjdb.log |grep -i DB_NAME
  db_name                  = "hjdb"
  db_name                  = "hjdb"
  db_name                  = "hjdb"

4.1.2.spfile/pfile檔案的引數設定資訊獲取

$ cat /tmp/inithjdb.ora |grep -i db_name
*.db_name='hjdb'
$ strings spfilehjdb |grep -i db_name
*.db_name='hjdb'

4.1.3.bbed從資料檔案頭獲取

位置block 1 offset 32-39

注意:這裡在配置bbed讀取檔案時,需要知道資料檔案的大小和file#,資料檔案大小可以透過dbfsize進行獲取確認,而file#可以透過作業系統dd+hexdump方式讀取block 1 offset 52獲取file#。

BBED> set file 1 block 1
  FILE#            1
  BLOCK#           1

BBED> p kcvfhhdr.kccfhdbn
text kccfhdbn[0]                            @32      H
text kccfhdbn[1]                            @33      J
text kccfhdbn[2]                            @34      D
text kccfhdbn[3]                            @35      B
text kccfhdbn[4]                            @36       
text kccfhdbn[5]                            @37       
text kccfhdbn[6]                            @38       
text kccfhdbn[7]                            @39

4.1.4.dd+strings也可以獲取

# 透過dd轉儲block 1
$ dd if=/tmp/SYSTEM.355.1164882483 of=/tmp/db_name_tbs skip=1 count=1 bs=8192
# 透過strings命令獲取字串DB_NAME
$ strings /tmp/db_name_tbs 
J-:B"hjdb"--dbname

4.2.線上日誌資訊獲取

4.2.1.獲取日誌大小

4.2.1.1.作業系統檢視

透過作業系統層檢視日誌檔案大小進行計算,需要減去block 0,再計算大小,因為block 0預留給作業系統記錄OS資訊的塊。

$ ls -lrt
total 1536016
-rw-r----- 1 oracle oinstall 524288512 Apr 12 10:34 o1_mf_13_lyhrzrws_.log
-rw-r----- 1 oracle oinstall 524288512 Apr 12 10:34 o1_mf_11_lyhrzh7c_.log
-rw-r----- 1 oracle oinstall 524288512 Apr 12 10:35 o1_mf_12_lyhrzn7p_.log
$ echo $(((524288512-512)/1024/1024)),透過作業系統層檢視的大小計算為500M
4.2.1.2.dbfsize檢視
$ dbfsize o1_mf_12_lyhrzn7p_.log
Database file: o1_mf_12_lyhrzn7p_.log
Database file type: file system
Database file size: 1024000 512 byte blocks

4.2.2.獲取日誌組號

4.2.2.1.redo檔案頭獲取
#透過dd命令轉儲block 1
$ dd if=o1_mf_12_lyhrzn7p_.log of=/tmp/redo12.log skip=1 count=1 bs=512
#透過hexdump以16進位制的方式從offset 48位開啟檢視
$ hexdump -s 48 -n 2 /tmp/redo12.log
0000030 000c --->group:12
4.2.2.2.檔名推測
o1_mf_11_lyhrzh7c_.log--->group 11
o1_mf_12_lyhrzn7p_.log--->group 12
o1_mf_13_lyhrzrws_.log--->group 13
4.2.2.3.控制檔案報錯

透過create controlfile命令報錯日誌提示,進行校正獲取group資訊。

ERROR at line 1:
ORA-01503: CREATE CONTROLFILE failed
ORA-01224: group number in header 11 does not match GROUP 1
ORA-01517: log member:
'/u01/app/oracle/oradata/HJDB/onlinelog/o1_mf_11_lyhrzh7c_.log'

透過以上方式,獲取到日誌檔案分別對應11、12、13,日誌大小為500M,blocksize為512。

LOGFILE
  GROUP 11 '/u01/app/oracle/oradata/HJDB/onlinelog/o1_mf_11_lyhrzh7c_.log'  SIZE 500M BLOCKSIZE 512,
  GROUP 12 '/u01/app/oracle/oradata/HJDB/onlinelog/o1_mf_12_lyhrzn7p_.log'  SIZE 500M BLOCKSIZE 512,
  GROUP 13 '/u01/app/oracle/oradata/HJDB/onlinelog/o1_mf_13_lyhrzrws_.log'  SIZE 500M BLOCKSIZE 512

4.3.資料檔案資訊獲取

4.3.1.資料檔案數量

當前在資料檔案目錄下發現有11個資料檔案。

$ ls -lrth
total 2.1G
-rw-r----- 1 oracle oinstall 5.1M Apr 17 15:00 o1_mf_users_m1k9dc1p_.dbf
-rw-r----- 1 oracle oinstall 546M Apr 17 15:00 o1_mf_undotbs1_m1k9dbyn_.dbf
-rw-r----- 1 oracle oinstall  11M Apr 17 15:00 o1_mf_test_m1k9d9vc_.dbf
-rw-r----- 1 oracle oinstall 921M Apr 17 15:00 o1_mf_system_m1k9dbyl_.dbf
-rw-r----- 1 oracle oinstall 531M Apr 17 15:00 o1_mf_sysaux_m1k9dbyp_.dbf
-rw-r----- 1 oracle oinstall  11M Apr 17 15:00 o1_mf_test_m1k9dc0t_.dbf
-rw-r----- 1 oracle oinstall  11M Apr 17 15:00 o1_mf_test_m1k9dbz0_.dbf
-rw-r----- 1 oracle oinstall  11M Apr 17 15:00 o1_mf_test_m1k9dbyy_.dbf
-rw-r----- 1 oracle oinstall  11M Apr 17 15:00 o1_mf_test_m1k9dbyw_.dbf
-rw-r----- 1 oracle oinstall  11M Apr 17 15:00 o1_mf_test5_m1k9dc18_.dbf
-rw-r----- 1 oracle oinstall  11M Apr 17 15:00 o1_mf_test1_m1k9dbyq_.dbf

4.3.2.file檔案號和表空間號

透過file$基表獲取file檔案號和表空間號資訊,存放在system file 1 block 233。

# 透過bbed開啟system file 1 block 233
# 可以看到kdbr結構有12行資料,代表最多使用過12個資料檔案
BBED> p kdbr
sb2 kdbr[0]                                 @86       8080
sb2 kdbr[1]                                 @88       7971
sb2 kdbr[2]                                 @90       7520
sb2 kdbr[3]                                 @92       7753
sb2 kdbr[4]                                 @94       7404
sb2 kdbr[5]                                 @96       7305
sb2 kdbr[6]                                 @98       7206
sb2 kdbr[7]                                 @100      7107
sb2 kdbr[8]                                 @102      7008
sb2 kdbr[9]                                 @104      6341
sb2 kdbr[10]                                @106      6810
sb2 kdbr[11]                                @108      6487

#檢視第一行資料kdbr[0]的offset
BBED> p *kdbr[0]
rowdata[1043]
-------------
ub1 rowdata[1043]                           @8148     0x2c

BBED> 
#檢視裡面的資料,col 0為file 1,col 1為status status 為2表示啟用,為1表示沒有使用,col 2 為資料檔案塊,col 3為表空間號,為null表示沒有使用
BBED> x /rnn offset 8148
rowdata[1043]                               @8148    
-------------
flag@8148: 0x2c (KDRHFL, KDRHFF, KDRHFH)
lock@8149: 0x00
cols@8150:   11

col    0[2] @8151: 1 
col    1[2] @8154: 2 
col    2[3] @8157: 64000 
col    3[1] @8161: 0 
col    4[2] @8163: 1 
col    5[5] @8166: 4194302 
col    6[3] @8172: 1280 
col    7[1] @8176: 0 
col    8[2] @8178: 7 
col    9[0] @8181: *NULL*
col   10[5] @8182: 4194306 
# 由於當前只有11個資料檔案,所以需要檢查每一行資料,確認是否存在資料檔案缺失,還是file$裡面記錄的是曾經使用過的資料檔案,這裡我們看到file#10的status為1,並且表空間號為null,代表資料檔案已經被刪除,只有11個資料檔案在使用。
BBED> x /rn offset 6409
rowdata[0]                                  @6409    
----------
flag@6409: 0x2c (KDRHFL, KDRHFF, KDRHFH)
lock@6410: 0x01
cols@6411:   11

col    0[2] @6412: 10 
col    1[2] @6415: 1 
col    2[3] @6418: 1280 
col    3[0] @6422: *NULL*
col    4[0] @6423: *NULL*
col    5[1] @6424: 0 
col    6[1] @6426: 0 
col    7[1] @6428: 0 
col    8[5] @6430: 3066083 
col    9[0] @6436: *NULL*
col   10[5] @6437: 41943042 

然後再使用bbed開啟每個資料檔案頭block 1的kccfhfno(offset 52)檔案號,kcvfhtsn(offset 332)表空間號與file$裡面記錄的檔案資訊進行一一對應,確保資料檔案數量一致。

BBED> p kcvfh.kcvfhhdr.kccfhfno
ub2 kccfhfno                                @52       0x0001

BBED> p kcvfh.kcvfhtsn
sword kcvfhtsn                              @332      0

確認完之後,我們就可以列出控制檔案需要的資料檔案資訊。

DATAFILE
'/u01/app/oracle/oradata/HJDB/datafile/o1_mf_undotbs1_m1k9dbyn_.dbf',
'/u01/app/oracle/oradata/HJDB/datafile/o1_mf_system_m1k9dbyl_.dbf',
'/u01/app/oracle/oradata/HJDB/datafile/o1_mf_sysaux_m1k9dbyp_.dbf',
'/u01/app/oracle/oradata/HJDB/datafile/o1_mf_users_m1k9dc1p_.dbf',
'/u01/app/oracle/oradata/HJDB/datafile/o1_mf_test_m1k9dbyy_.dbf',
'/u01/app/oracle/oradata/HJDB/datafile/o1_mf_test_m1k9dbyw_.dbf',
'/u01/app/oracle/oradata/HJDB/datafile/o1_mf_test_m1k9d9vc_.dbf',
'/u01/app/oracle/oradata/HJDB/datafile/o1_mf_test1_m1k9dbyq_.dbf',
'/u01/app/oracle/oradata/HJDB/datafile/o1_mf_test_m1k9dc0t_.dbf',
'/u01/app/oracle/oradata/HJDB/datafile/o1_mf_test_m1k9dbz0_.dbf',
'/u01/app/oracle/oradata/HJDB/datafile/o1_mf_test5_m1k9dc18_.dbf'

4.4.資料庫的字符集獲取

character儲存在基表props$下面,Oracle11g 在system file 1 block 801,Oracle19c 在system file 1 block 1321。

透過bbed讀取system file 1 block 801獲取。

BBED> set file 1 block 801
        FILE#           1
        BLOCK#          801

BBED> set count 8196
        COUNT           8196

BBED> set offset 7100
        OFFSET          7100

BBED> dump /v
 File: /u01/app/oracle/oradata/HJDB/datafile/o1_mf_system_m1k9dbyl_.dbf (1)
 Block: 801     Offsets: 7100 to 8191  Dba:0x00400321
-------------------------------------------------------
 69737469 63206465 66696e69 74696f6e l istic definition
 2c000311 4e4c535f 44415445 5f4c414e l ,...NLS_DATE_LAN
 47554147 4508414d 45524943 414e0d44 l GUAGE.AMERICAN.D
 61746520 6c616e67 75616765 2c00030f l ate language,...
 4e4c535f 44415445 5f464f52 4d415409 l NLS_DATE_FORMAT.
 44442d4d 4f4e2d52 520b4461 74652066 l DD-MON-RR.Date f
 6f726d61 742c0003 0c4e4c53 5f43414c l ormat,...NLS_CAL
 454e4441 52094752 45474f52 49414e0f l ENDAR.GREGORIAN.
 43616c65 6e646172 20737973 74656d2c l Calendar system,
 0103104e 4c535f43 48415241 43544552 l ...NLS_CHARACTER
 53455408 414c3332 55544638 0d436861 l SET.AL32UTF8.Cha  ---字符集
 72616374 65722073 65742c00 03164e4c l racter set,...NL
 535f4e55 4d455249 435f4348 41524143 l S_NUMERIC_CHARAC

透過dd+strings方式獲取。

$ dd if=/tmp/SYSTEM.292.1151425093  of=/tmp/system_char skip=801 count=1 bs=8192
$ strings system_char 

NLS_DATE_LANGUAGE
AMERICAN
Date language,
NLS_DATE_FORMAT  DD-MON-RR
Date format,
NLS_CALENDAR  GREGORIAN
Calendar system,
NLS_CHARACTERSET
AL32UTF8
Character set,
NLS_NUMERIC_CHARACTERS
Numeric characters,
NLS_ISO_CURRENCY
AMERICA
ISO currency,
NLS_CURRENCY

5.建立控制檔案

透過以上準備,我們獲取到了手動恢復建立控制檔案的基本資訊。

CREATE CONTROLFILE REUSE DATABASE "HJDB" NORESETLOGS  ARCHIVELOG
    MAXLOGFILES 13
    MAXLOGMEMBERS 3
    MAXDATAFILES 20
    MAXINSTANCES 3
    MAXLOGHISTORY 1024
LOGFILE
  GROUP 11 '/u01/app/oracle/oradata/HJDB/onlinelog/o1_mf_11_lyhrzh7c_.log'  SIZE 500M BLOCKSIZE 512,
  GROUP 12 '/u01/app/oracle/oradata/HJDB/onlinelog/o1_mf_12_lyhrzn7p_.log'  SIZE 500M BLOCKSIZE 512,
  GROUP 13 '/u01/app/oracle/oradata/HJDB/onlinelog/o1_mf_13_lyhrzrws_.log'  SIZE 500M BLOCKSIZE 512
-- STANDBY LOGFILE
DATAFILE
'/u01/app/oracle/oradata/HJDB/datafile/o1_mf_undotbs1_m1k9dbyn_.dbf',
'/u01/app/oracle/oradata/HJDB/datafile/o1_mf_system_m1k9dbyl_.dbf',
'/u01/app/oracle/oradata/HJDB/datafile/o1_mf_sysaux_m1k9dbyp_.dbf',
'/u01/app/oracle/oradata/HJDB/datafile/o1_mf_users_m1k9dc1p_.dbf',
'/u01/app/oracle/oradata/HJDB/datafile/o1_mf_test_m1k9dbyy_.dbf',
'/u01/app/oracle/oradata/HJDB/datafile/o1_mf_test_m1k9dbyw_.dbf',
'/u01/app/oracle/oradata/HJDB/datafile/o1_mf_test_m1k9d9vc_.dbf',
'/u01/app/oracle/oradata/HJDB/datafile/o1_mf_test1_m1k9dbyq_.dbf',
'/u01/app/oracle/oradata/HJDB/datafile/o1_mf_test_m1k9dc0t_.dbf',
'/u01/app/oracle/oradata/HJDB/datafile/o1_mf_test_m1k9dbz0_.dbf',
'/u01/app/oracle/oradata/HJDB/datafile/o1_mf_test5_m1k9dc18_.dbf'
CHARACTER SET AL32UTF8;

6.開啟資料庫

1 將資料庫啟動到nomount。

2 執行控制檔案建立語句。

3 recover DATABASE恢復資料庫。

4 alter database open開啟資料庫。

此文覺得很好,為了防止丟失,特記錄下來。原文:公眾號-勇敢牛牛的筆記-Oracle-無備份情況下,如何手動恢復控制檔案

相關文章