Oracle-无备份情况下,如何手动恢复控制文件
1.测试场景
本文主要模拟在控制文件没有备份的情况下丢失,如何根据已有的参数文件、数据文件、在线日志信息去手动生成控制文件。
2.测试环境
Oracle单实例:11.2.0.4
数据文件目录:/u01/app/oracle/oradata/HJDB/datafile
在线日志目录:/u01/app/oracle/oradata/HJDB/onlinelog
3.创建文件所需要的信息和选项
以下这些选项跟数据库的参数文件、数据文件、在线日志没有强关联性,可以自行根据环境需要进行设置。
-
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
-
NORESETLOGS选项
如果数据库是完整的恢复,包含完整的在线日志,可以选择NORESETLOGS方式创建。
如果数据库是不完整的恢复,需要选择RESETLOGS方式创建。
-
FORCE LOGGING选项
数据库是否开启force logging 。
-
ARCHIVELOG/NOARCHIVELOG选项
数据库归档模式。
-
MAXLOGFILES选项
设置创建的控制文件的日志组数量,要大于当前的在线日志组group的大小,比如日志组有3组,分别为11,12,13,则MAXLOGFILES设置要大于13。
-
MAXLOGMEMBERS选项
设置创建的控制文件每个日志组的成员最大数量,通常为1-2。
-
MAXDATAFILES选项
设置创建的控制文件的最大数据文件数量,大于当前的数据文件数量,不超过db_files即可。
-
MAXINSTANCES选项
设置可以同时挂载和打开数据库的最大实例数。
-
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-无备份情况下,如何手动恢复控制文件