作者:dbtan |【转载时请以超链接形式标明文章出处作者信息】


Redo故障的恢复:

我们已经知道日志文件对于数据库来说非常重要,在实际使用过程中,可以会遇到各种各样的问题,接下来将介绍一些在日常数据库维护中经常会遇到的情况。

1. 丢失非活动日志组的故障恢复:
如果数据库丢失的是非活动(INACTIVE)日志组,由于非活动日志组已经完成检查点,数据库不会发生数据损失,此时只需要通过Clear重建该日志组即可恢复。
⑴ 首先删除一个非活动日志组,模拟一次故障损失:

sys@TQGZS> ! mv /u01/oracle/oradata/tqgzs/redo02.log /u01/oracle/databak/

⑵ 如果数据库日志切换,使用到该日志组,则数据库可能马上崩溃:

sys@TQGZS> alter system switch logfile;
alter system switch logfile
*
ERROR at line 1:
ORA-03113: end-of-file on communication channel

⑶ 可以从警告日志中获得部分详细信息:

Sun Dec 20 21:01:57 2009
Errors in file /u01/oracle/admin/tqgzs/bdump/tqgzs_arc1_5411.trc:
ORA-00313: open failed for members of log group 2 of thread 1
ORA-00312: online log 2 thread 1: '/u01/oracle/oradata/tqgzs/redo02.log'
ORA-27037: unable to obtain file status
Linux Error: 2: No such file or directory
Additional information: 3
Sun Dec 20 21:01:57 2009

⑷ 此时启动数据库,数据库会提示日志丢失:

idle> startup
ORACLE instance started.

Total System Global Area  285212672 bytes
Fixed Size                  1218992 bytes
Variable Size              83887696 bytes
Database Buffers          197132288 bytes
Redo Buffers                2973696 bytes
Database mounted.
ORA-00313: open failed for members of log group 2 of thread 1
ORA-00312: online log 2 thread 1: '/u01/oracle/oradata/tqgzs/redo02.log'

⑸ 此时在MOUNT状态,可以查看各日志组及日志文件的状态:

idle> select * from v$log;
    GROUP#    THREAD#  SEQUENCE#      BYTES    MEMBERS ARC STATUS           FIRST_CHANGE# FIRST_TIM
---------- ---------- ---------- ---------- ---------- --- ---------------- ------------- ---------
         1          1        142   52428800          1 NO  CURRENT                6278352 20-DEC-09
         3          1        141   52428800          1 NO  INACTIVE               6278348 20-DEC-09
         2          1        140   52428800          1 NO  INACTIVE               6278311 20-DEC-09

idle> select * from v$logfile;
    GROUP# STATUS  TYPE    MEMBER                                                       IS_
---------- ------- ------- ------------------------------------------------------------ ---
         3         ONLINE  /u01/oracle/oradata/tqgzs/redo03.log                         NO
         2         ONLINE  /u01/oracle/oradata/tqgzs/redo02.log                         NO
         1         ONLINE  /u01/oracle/oradata/tqgzs/redo01.log                         NO

可以注意到,v$log和v$logfile中依然有redo02记录。

⑹ 数据库处于归档模式下,清楚该未完成归档的日志组(redo02)后,即可启动数据库:

idle> alter database clear unarchived logfile group 2;
Database altered.
idle> alter database open;
Database altered.
idle> conn / as sysdba
Connected.
sys@TQGZS>

如果数据库在非归档模式下,使用如下命令强制清除:

alter database clear logfile group 2;

打开数据库之后,再次查询v$log和v$logfile视图,可以看到GROUP#=2已经为CURRENT了,一切恢复正常。

sys@TQGZS> select * from v$log;
    GROUP#    THREAD#  SEQUENCE#      BYTES    MEMBERS ARC STATUS           FIRST_CHANGE# FIRST_TIM
---------- ---------- ---------- ---------- ---------- --- ---------------- ------------- ---------
         1          1        142   52428800          1 YES INACTIVE               6278352 20-DEC-09
         3          1        141   52428800          1 YES INACTIVE               6278348 20-DEC-09
         2          1        143   52428800          1 NO  CURRENT                6278714 20-DEC-09
sys@TQGZS> select * from v$logfile;
    GROUP# STATUS  TYPE    MEMBER                                                       IS_
---------- ------- ------- ------------------------------------------------------------ ---
         3         ONLINE  /u01/oracle/oradata/tqgzs/redo03.log                         NO
         2         ONLINE  /u01/oracle/oradata/tqgzs/redo02.log                         NO
         1         ONLINE  /u01/oracle/oradata/tqgzs/redo01.log                         NO
sys@TQGZS> alter system switch logfile;
System altered.
sys@TQGZS> alter system switch logfile;
System altered.
sys@TQGZS> select * from v$log;
    GROUP#    THREAD#  SEQUENCE#      BYTES    MEMBERS ARC STATUS           FIRST_CHANGE# FIRST_TIM
---------- ---------- ---------- ---------- ---------- --- ---------------- ------------- ---------
         1          1        145   52428800          1 NO  CURRENT                6280518 20-DEC-09
         3          1        144   52428800          1 YES ACTIVE                 6280516 20-DEC-09
         2          1        143   52428800          1 YES ACTIVE                 6278714 20-DEC-09

 

2. 丢失活动或当前日志文件的恢复:
虽然Oracle通过日志文件保证提交成功的数据不丢失,但是在故障中我们可能会损失当前的(CURRENT)日志文件,这又可分为两种情况。

① 在损失当前日志时,如果数据库是正常关闭的:
由于关闭数据库前,Oracle会执行全面检查点,当前日志在实例恢复中可以不再需要。
在Oracle 8i中,可以通过如下步骤恢复(非归档模式下测试过程):

> select * from v$log;
> shutdown immediate;
> ! mv /u01/oracle/oradata/tqgzs/redo* /tmp
> startup
> alter database clear logfile group 1;
> alter database clear logfile group 2;
> alter database clear logfile group 3;
> alter database open;

在Oracle 9i中,可能无法对于当前日志进行Clear,需要通过Until Cancel恢复后,Resetlogs打开,以下是一个简单的测试过程:

> ! rm /u01/oracle/oradata/tqgzs/redo0*
> startup
> alter database clear logfile group 1;
> alter database clear unarchived logfile group 2;
alter database clear unarchived logfile group 2
*
ERROR at line 1:
ORA-00313: open failed for members of log group 2 of thread 1
ORA-00312: online log 2 thread 1: '/u01/oracle/oradata/tqgzs/redo02.log'
ORA-27037: unable to obtain file status
Linux Error: 2: No such file or directory
Additional information: 3
> recover database until cancel;
> alter database open resetlogs;

② 在损失当前日志时,如果数据库是异常关闭的:
那么Oracle在进行实例恢复时必须要求当前日志,否则Oracle将无法保证提交成功的数据不丢失(也就意味着Oracle会丢失数据),在这种情况下,Oracle数据库将无法启动。

对于这种情况,通常需要从备份中恢复数据文件,通过应用归档日志文件向前推演,直到最后一个完好的日志文件,然后可以通过resetlogs启动数据库完成恢复。丢失的数据就是损坏的日志文件中的数据。这种恢复方式与以上介绍的方法类似,不再赘述。

可是不幸的是,很多数据库是从不备份的,那么在面对这种情况时,Oracle提供给我们一种内部手段可以用于强制性数据库打开,忽略一致性等问题,在打开数据库之后,Oracle建议导出(exp)数据,然后重建数据库,再导入(imp)数据,完成灾难恢复。

在继续之前,我愿意提及一下我经常强调的DBA四大守则之一:备份重于一切。要知道系统总是要崩溃的,没有有效的备份只是等哪一天死而已。如果说有什么事可以让DBA在深夜惊醒的话,那就是“没有备份”。

Oracle有一类具有特殊作用的隐含参数,其中一个参数是_allow_resetlogs_corruption,来看一下这个参数的说明:

sys@TQGZS> @GetParDescrb.sql
Enter value for par: _allow_resetlogs_corruption
old   4:    AND x.ksppinm LIKE '%&par%'
new   4:    AND x.ksppinm LIKE '%_allow_resetlogs_corruption%'
NAME                           VALUE                DESCRIB
------------------------------ -------------------- ------------------------------------------------------------
_allow_resetlogs_corruption    FALSE                allow resetlogs even if it will cause corruption

该参数的含义是,允许在破坏一致性的情况下强制重置日志,打开数据库。_allow_resetlogs_corruption将使用所有数据文件最旧的SCN打开数据库,所以通常需要保证SYSTEM表空间拥有最旧的SCN。在强制打开数据库后,可能因为各种原因伴随出现ORA-600错误,有些可以依据常规途径解决。

步骤如下:
> alter system set "_allow_resetlogs_corruption"=true scope=spfile;
> shutdown immediate;
> startup mount;
> recover database using backup controlfile until cancel;
canel
> alter database open resetlogs;
> shutdown immediate;
> startup

幸运的时候数据库就可以成功OPEN,如果不幸则可能会遇到一系统的ORA-600错误(最常见的是2662错误),此时就需要使用多种手段继续进行调整恢复。

如果注意观察alert日志,可能会发现类似以下日志:

Fri Jun 10 16:30:25 2005
alter database open resetlogs
Fri Jun 10 16:30:25 2005
RESETLOGS is being done without consistancy checks. This may result
in a corrupted database. The database should be recreated.
RESETLOGS after incomplete recovery UNTIL CHANGE 240677200
Resetting resetlogs activation ID 3171937922 (0xbd0fee82)

不一致恢复最后恢复到的Change号是240677200。

Oracle告诉我们,强制resetlogs跳过了一致性检查,可能导致数据库损坏,数据库应当重建。而且此方法应该在Oracle技术支持的指导之下进行,否则Oracle将不对采用此类方式进行恢复的数据库进行支持。

DBA需要时刻铭记的一个工作习惯是,在重要操作或故障处理前,保留现场。也就是说在进行以上类似恢复等工作前,我们应当对数据库进行冷备份,这样在恢复尝试失败后,也仍然可以回退到之前的状态。

- The End -