Oracle数据库无备份强制恢复实战:SCN不一致、oradebug与ORA-600[2662]
这不是教程,这是一次真实恢复过程记录。海关项目的Oracle数据库,没有备份,控制文件损坏,日志文件损坏,数据文件有损坏。最终虽然没有完全恢复成功,但过程中积累的SCN机制、oradebug修改SCN、隐藏参数等知识,值得记录。
背景
某项目Oracle数据库挂了。现象:
- 登录不了(重置了密码,
orapwd命令) - 启动提示控制文件不一致(复制了备份的控制文件,但这步有问题)
- 控制文件损坏(发现有数据文件也有损坏,去除后能够建立控制文件)
- 清理了日志文件
- 恢复了数据文件
- 修改了
_allow开头的隐藏参数 - 打开数据报ORA-00600 [2662]错误
没有RMAN备份,没有expdp导出。只能硬着头皮强制恢复。
一、强制打开数据库的关键步骤
如果实在要强制打开数据库,参考如下关键点,再有其他错误就要一个一个看了,很麻烦。
步骤1:允许resetlogs时有脏数据
_alter system set "_allow_resetlogs_corruption"=true scope=spfile;这个参数允许在open resetlogs时数据文件中有不一致数据。Oracle官方不建议使用,但没备份的时候,这就是最后一根稻草。
步骤2:处理ORA-01555错误
如果出现ORA-01555错误导致数据库无法open,设置:
_CORRUPTED_ROLLBACK_SEGMENTS undo_management = 'MANUAL'把回滚段标记为损坏,用MANUAL模式绕过自动undo管理。
步骤3:处理ORA-600 [2662]——SCN不一致
ORA-600 [2662]是SCN不一致的典型错误。参数含义:
| 参数 | 含义 |
|---|---|
| Arg [a] | Current SCN WRAP:当前(控制文件)的SCN WRAP |
| Arg [b] | Current SCN BASE:当前(控制文件)的SCN BASE |
| Arg [c] | dependent SCN WRAP:目标SCN WRAP |
| Arg [d] | dependent SCN BASE:目标SCN BASE |
SCN的计算公式:
SCN = (SCN_WRAP × 4294967296) + SCN_BASE其中4294967296 = 2^32。SCN_WRAP是高位,SCN_BASE是低位。当SCN_BASE足够大时,SCN_WRAP就会加1。
处理方法:先通过多次重启open的方法来观察Current SCN BASE增长速度。如果Current SCN BASE和dependent SCN BASE相差不远,重启几次数据库就可能打开。
步骤4:用10015事件加速SCN增长
如果差距较远,mount之后执行:
alter session set events '10015 trace name adjust_scn level 10';然后尝试open。这个事件会加速Current SCN BASE的增长。
步骤5:启用错误模拟让10015事件生效
如果加入10015事件adjust_scn之后,Current SCN BASE增长还是很慢,某些版本必须加入:
_allow_error_simulation = TRUE才能使10015事件生效。
步骤6:用_smu_debug_mode加速SCN WRAP增长
如果Current SCN BASE增长还是很慢:
_smu_debug_mode = 268435456这个参数直接增长SCN WRAP,需要和_allow_error_simulation=true同时使用。
步骤7:用_minimum_giga_scn大步推进
_minimum_giga_scn = n把SCN向前推进nG。只有Current SCN和dependent SCN相差nG时这个参数才起作用,否则无效。
步骤8:处理ORA-600[6006]和ORA-600[4137]
如果SCN号一致以后报ORA-600[6006]或ORA-600[4137],需要添加:
*.event="10513 trace name context forever,level 2" *.db_block_checking=false步骤9:open resetlogs后的建议
对于open resetlogs打开以后的数据库,最好将业务用户导出以后重建数据库,以防止数据库出现不可预知的错误。Oracle官方建议是open resetlogs之后需要重建数据库。
二、Oracle 11.2.0.4的SCN改法——oradebug实战
上面的参数方法在某些版本不够直接。Oracle 11.2.0.4可以用oradebug直接修改SGA中的SCN值。
第一步:计算目标SCN的十六进制值
SQL> select to_char(2723797,'XXXXXXXXXXXXXXXX') from dual; TO_CHAR(2723797,' ----------------- 298FD52723797的十六进制是0x298FD5。
第二步:设置oradebug跟踪自己的进程
SQL> oradebug setmypid Statement processed.第三步:查看当前SGA中的SCN值
SQL> oradebug dumpvar sga kcsgscn_ kcslf kcsgscn_ [06001AE70, 06001AEA0) = 00000000 00000000 00000000 ...当前SCN是0,数据库处于mount状态。
第四步:用oradebug poke直接修改SCN
SQL> oradebug poke 0x06001AE70 8 0x0000000000298FD5 BEFORE: [06001AE70, 06001AE78) = 00000000 00000000 AFTER: [06001AE70, 06001AE78) = 00298FD5 00000000poke命令的参数:地址、长度、新值。8表示8字节。
第五步:验证修改后的SCN
SQL> oradebug dumpvar sga kcsgscn_ kcslf kcsgscn_ [06001AE70, 06001AEA0) = 00298FD5 00000000 ...SCN已经从0变成了0x298FD5(即2723797)。
第六步:打开数据库
SQL> alter database open; Database altered.第七步:验证checkpoint SCN
SQL> select checkpoint_change#, checkpoint_change#/1024/1024/1024 SCN_WARP from v$database; CHECKPOINT_CHANGE# SCN_WARP ------------------ ---------- 2723798 .002536735数据库成功打开,checkpoint SCN已经更新。
参数速查表
| 参数/事件 | 作用 | 备注 |
|---|---|---|
_allow_resetlogs_corruption=TRUE | 允许resetlogs时有脏数据 | 强制打开的最后手段 |
_allow_terminal_recovery_corruption=TRUE | 允许终端恢复时有损坏 | 配合上面一起用 |
_CORRUPTED_ROLLBACK_SEGMENTS | 标记损坏的回滚段 | 处理ORA-01555 |
undo_management=MANUAL | 手动undo管理 | 绕过损坏的undo表空间 |
event 10015 adjust_scn | 加速SCN BASE增长 | 需要配合_allow_error_simulation |
_allow_error_simulation=TRUE | 允许内部错误模拟 | 让10015事件生效 |
_smu_debug_mode=268435456 | 直接增长SCN WRAP | 配合_allow_error_simulation |
_minimum_giga_scn=n | SCN向前推进nG | 差距大时使用 |
event 10513 level 2 | 禁止事务恢复 | 处理ORA-600[6006] |
oradebug poke | 直接修改SGA中的SCN | 11.2.0.4可用 |
反思
这次恢复最终没有完全成功。但过程中学到的教训:
- 没有备份就不要碰生产数据库——这次是从"没备份"开始的灾难链
- SCN是Oracle的心跳——理解SCN的WRAP/BASE结构是处理ORA-600[2662]的前提
- oradebug poke是核武器——直接修改SGA内存,用错了数据库就彻底废了
- 强制恢复后的数据库不可信——Oracle官方建议重建,这不是建议,是忠告
结果:未完全恢复,但积累了宝贵的强制恢复经验