非归档环境跳过归档恢复数据文件

1. 简要说明

总是在用到归档日志时,才发现某个归档日志已经丢失。总是要在数据库无法打开时,才发现数据库是非归档。
本篇文章解释,如何在缺失归档日志或者是非归档的情况下,跳过归档日志进行恢复。当然这种恢复模式会丢失数据,尽量不使用,但是在没有备份的情况下,丢失数据,与尽可能地恢复数据,孰轻孰重,就需要自已判断了。不废话多说了,直接切入正题

2. 环境说明

非归档环境,数据库的文件和表空间信息

SQL> select name, ts# from v$datafile;

NAME                                   TS#
------------------------------------- ----
/data/oradata/test10/system01.dbf        0
/data/oradata/test10/undotbs01.dbf       1
/data/oradata/test10/sysaux01.dbf        2
/data/oradata/test10/users01.dbf         4
/data/oradata/test10/tbs_test_02.dbf     6
/data/oradata/test10/tbs_test11.dbf      7

SQL> select name from v$tablespace where ts# = 7;

NAME
--------------
TBS_TEST2

3. 生成故障环境

模拟数据文件故障,无备份,非归档,无法进行数据文件恢复。
模拟的办法,先做个冷备,然后打开库,做一些业务,切几次重做日志,然后再停库,把6号文件拿冷备替换,再次打开库时,6号文件就需要恢复了。

SQL> alter database open;
alter database open
*
ERROR at line 1:
ORA-01113: file 6 needs media recovery if it was restored from backup, or END
BACKUP if it was not
ORA-01110: data file 6: '/data/oradata/test10/tbs_test11.dbf'

SQL> alter session set nls_date_format='YYYY-MM-DD HH24:MI:SS';
Session altered.

SQL> set linesize 160
SQL> select * from v$recover_file;

 FILE# ONLINE  ONLINE_ ERROR        CHANGE# TIME
------ ------- ------- --------- ---------- -------------------
     6 ONLINE  ONLINE               8018892 2016-05-16 09:37:50

SQL> recover datafile 6;
ORA-00279: change 8018892 generated at 05/16/2016 09:37:50 needed for thread 1
ORA-00289: suggestion : /data/oradata/arch/test10/1_402_894885766.dbf
ORA-00280: change 8018892 for thread 1 is in sequence #402

Specify log: {<RET>=suggested | filename | AUTO | CANCEL}
CANCEL
Media recovery cancelled.

4. 检查当前redo信息

SQL> select * from v$log;

GROUP# THREAD# SEQUENCE#    BYTES MEMBERS ARC STATUS   FIRST_CHANGE# FIRST_TIME
------ ------- --------- -------- ------- --- -------- ------------- -------------------
     1       1       412 52428800       1 NO  CURRENT        8019466 2016-05-16 09:40:25
     3       1       411 52428800       1 YES INACTIVE       8019449 2016-05-16 09:40:23
     2       1       410 52428800       1 YES INACTIVE       8019444 2016-05-16 09:40:22

SQL> column name format a60
SQL> select file#, name from v$datafile;

     FILE# NAME
---------- ------------------------------------
         1 /data/oradata/test10/system01.dbf
         2 /data/oradata/test10/undotbs01.dbf
         3 /data/oradata/test10/sysaux01.dbf
         4 /data/oradata/test10/users01.dbf
         5 /data/oradata/test10/tbs_test_02.dbf
         6 /data/oradata/test10/tbs_test11.dbf

 6 rows selected.

5. 检查问题文件头信息

这里就需要使用BBED了,如何编译BBED,自行查找说明

$ bbed filename=/data/oradata/test10/tbs_test11.dbf blocksize=8192 password=blockedit

BBED> set block 1
        BLOCK#          1

BBED> map
 File: /data/oradata/test10/tbs_test11.dbf (0)
 Block: 1                                     Dba:0x00000000
------------------------------------------------------------
 Data File Header
 struct kcvfh, 676 bytes                    @0
 ub4 tailchk                                @8188    

BBED> p kcvfh
struct kcvfh, 676 bytes                     @0
   struct kcvfhbfh, 20 bytes                @0
      ub1 type_kcbh                         @0        0x0b
      ub1 frmt_kcbh                         @1        0xa2
......
   struct kcvfhckp, 36 bytes                @484
      struct kcvcpscn, 8 bytes              @484                    --> 修改
         ub4 kscnbas                        @484      0x007a5bcc
         ub2 kscnwrp                        @488      0x0000
      ub4 kcvcptim                          @492      0x365bcfee    --> 修改
      ub2 kcvcpthr                          @496      0x0001
      union u, 12 bytes                     @500
         struct kcvcprba, 12 bytes          @500                    --> 修改
            ub4 kcrbaseq                    @500      0x00000192
            ub4 kcrbabno                    @504      0x000001d8
            ub2 kcrbabof                    @508      0x0010
......

当前有问题的数据文件,恢复需要的重做日志的sequence是0x00000192转成十进制为402,与前面recover datafile需要402号归档日志一致,当前数据库为非归档,就肯定没有402号归档日志了。

6. 检查正常文件头信息

此处只模拟坏了一个文件,所以可以通过与好的文件交叉比对,如果所有文件都损坏了,那就只能查v$log信息,选择最小的SCN信息了。

$ bbed filename=/data/oradata/test10/tbs_test_02.dbf blocksize=8192 password=blockedit

BBED> set block 1
        BLOCK#          1

BBED> p kcvfh.kcvfhckp
struct kcvfhckp, 36 bytes                   @484
   struct kcvcpscn, 8 bytes                 @484
      ub4 kscnbas                           @484      0x007a5ed5
      ub2 kscnwrp                           @488      0x0000
   ub4 kcvcptim                             @492      0x365bd094
   ub2 kcvcpthr                             @496      0x0001
   union u, 12 bytes                        @500
      struct kcvcprba, 12 bytes             @500
         ub4 kcrbaseq                       @500      0x0000019c
         ub4 kcrbabno                       @504      0x0000013a
         ub2 kcrbabof                       @508      0x0010
......

7. 修改问题文件头的SCN和sequence信息

struct kcvcpscn的kscnbas、kscnwrp,这两个字节,是修改的重点。
kscnwrp 对应高16位,kscnbas是低32位,具体结构如下:
0xffff.ffffffff

当前v$log中最小的sequence#是410,相应的first_change#是:8019444,转成16进制为:007A5DF4,所以
kscnwrp = 0x0000
kscnbas = 0x007a5df4

BBED> m /x f45d offset 484         --> offset 486位置不需要改,数值一致
BBED> m /x 9a01 offset 500 

kcvcptim可以不改

以下修改是把SCN修改成其它数据文件一致,但实际可以改成v$log中的最小first_change#

$ bbed filename=/data/oradata/test10/tbs_test11.dbf blocksize=8192 password=blockedit

BBED> set mode edit
        MODE            Edit

BBED> set block 1
        BLOCK#          1

BBED> m /x d55e offset 484
BBED> m /x 94d0 offset 492
BBED> m /x 9c01 offset 500                  --> 这个可以先尝试修改为0x019a = 410

BBED> p kcvfh.kcvfhckp
struct kcvfhckp, 36 bytes                   @484
   struct kcvcpscn, 8 bytes                 @484
      ub4 kscnbas                           @484      0x007a5ed5
      ub2 kscnwrp                           @488      0x0000
   ub4 kcvcptim                             @492      0x365bd094
   ub2 kcvcpthr                             @496      0x0001
   union u, 12 bytes                        @500
      struct kcvcprba, 12 bytes             @500
         ub4 kcrbaseq                       @500      0x0000019c
         ub4 kcrbabno                       @504      0x000001d8
         ub2 kcrbabof                       @508      0x0010

BBED> verify
DBVERIFY - Verification starting
FILE = /data/oradata/test10/tbs_test11.dbf
BLOCK = 1

Block 1 is corrupt
Corrupt block relative dba: 0x01800001 (file 0, block 1)
Bad check value found during verification
Data in bad block:
 type: 11 format: 2 rdba: 0x01800001
 last change scn: 0x0000.00000000 seq: 0x1 flg: 0x04
 spare1: 0x0 spare2: 0x0 spare3: 0x0
 consistency value in tail: 0x00000b01
 check value in block header: 0x9d87
 computed block checksum: 0x1a6d

DBVERIFY - Verification complete

Total Blocks Examined         : 1
Total Blocks Processed (Data) : 0
Total Blocks Failing   (Data) : 0
Total Blocks Processed (Index): 0
Total Blocks Failing   (Index): 0
Total Blocks Empty            : 0
Total Blocks Marked Corrupt   : 1
Total Blocks Influx           : 0

BBED> sum apply
Check value for File 0, Block 1:
current = 0x87ea, required = 0x87ea

8. 恢复数据文件

SQL> recover datafile 6;
Media recovery complete.
SQL> alter database open;
Database altered.

数据库打开后,可能会碰到坏块问题,建议设置10231 Event,并导出数据重建表空间或库。

SQL> ALTER SYSTEM SET EVENTS '10231 TRACE NAME CONTEXT FOREVER, LEVEL 10';

9. 如何有大量的数据文件需要跳过归档日志该如何处理

生产库一般有大量的文件,如果使用BBED一个个去改,那真是太费劲了,而且不能保证全部改正确。
这时侯就要使用脚本了,编写了个脚本如下:

$ cat bbed_recover.sh
bbed FILENAME=$1    SILENT=yes  PASSWORD=blockedit<<EOF 
set block 1 
set mode edit 

set offset 484 
modify /x f45d 

set offset 492 
modify /x 94d0 

set offset 500 
modify /x 9a01 

verify 
sum apply
EOF

使用方法如下:

$ bbed_recover.sh /data/oradata/test10/xxxx.dbf

然后再到sqlplus里

SQL> recover datafile '/data/oradata/test10/xxxx.dbf'

所有数据文件全部恢复完再打开数据库

关于紫砂壶

感悟技术人生
此条目发表在Internal, Oracle故障诊断分类目录,贴了, 标签。将固定链接加入收藏夹。