dd复制新库的block修复bootstrap

问题背景:存储损坏导致数据库产生坏块无法启动,经过一堆动作以后,卡在file 1 block 45发生Fractured block坏块
OS: windows 
db: 11.1.0.6.0
无备份,未开归档
Hex dump of (file 1, block 45) in trace file d:\app\administrator\diag\rdbms\...\...\trace\..._ora_3564.trc
Corrupt block relative dba: 0x0040002d (file 1, block 45)
Fractured block found during buffer read
Data in bad block:
type: 6 format: 2 rdba: 0x0040002d
last change scn: 0x0000.5c7fd3a0 seq: 0x1 flg: 0x06
spare1: 0x0 spare2: 0x0 spare3: 0x0
consistency value in tail: 0x7b2c0601
check value in block header: 0x1d5
computed block checksum: 0xcfea
Reread of rdba: 0x0040002d (file 1, block 45) found same corrupted data
Errors in file d:\app\administrator\diag\rdbms\...\...\trace\..._ora_3564.trc (incident=592148):
ORA-01578: ORACLE 数据块损坏 (文件号 1, 块号 45)
ORA-01110: 数据文件 1: 'G:\DATAFILE\...\SYSTEM01.DBF'
Incident details in: d:\app\administrator\diag\rdbms\...\...\incident\incdir_592148\..._ora_3564_i592148.trc
Errors in file d:\app\administrator\diag\rdbms\...\...\trace\..._ora_3564.trc:
ORA-00704: 引导程序进程失败
ORA-00604: 递归 SQL 级别 1 出现错误
ORA-01578: ORACLE 数据块损坏 (文件号 1, 块号 45)
ORA-01110: 数据文件 1: 'G:\DATAFILE\...\SYSTEM01.DBF'
最后求助oracle,oracle找了个案例
使用dd工具,在正常的数据库上进行dd
dd if=XXXX\SYSTEM01.DBF skip=45 of=XXX\45.out bs=8k count=1   
备份当前问题数据库的SYSTEM01.DBF文件,然后拷贝之前产生的45.out文件到本机,进行dd复制
dd if=XXXX\45.out seek=45 of=XXXX\SYSTEM01.DBF bs=8k count=1
然后启动数据库成功。
大家对这种非常规的恢复方法有没有什么经验和心得?
另外,之前还报错
ORA-00704: 引导程序进程失败
ORA-00704: 引导程序进程失败
ORA-00604: 递归 SQL 级别 1 出现错误
ORA-01555: 快照过旧: 回退段号 10 (名称为 "_SYSSMU10_1192467665$") 过小
使用
_CORRUPTED_ROLLBACK_SEGMENTS
  alter session  set events '10015 trace name adjust_scn level 10';
  _allow_error_simulation  = TRUE
  _smu_debug_mode = 268435456
  _minimum_giga_scn
均没有跳过。

最后用
oradebug DUMPvar SGA kcsgscn_
oradebug poke 
直接修改scn搞定,但是oradebug poke的参数不是很明白,当时随便写了个数字。
oradebug poke 地址 8 0xXXXXXX时报错第二个参数只能是1,2,4(未保留日志)
改成4以后,0xXXXXXX写的是v$datafile_header里面的scn(所有文件都一样),但是报错值太大了。
用SQL查current_scn是0,所以最后0xXXXXX随便写了个0A,报错过去了。
但是最后两个参数的具体含义和算法不太清除,希望各位不吝赐教,多谢。

 
 
测试环境1:
大端序

5~8字节表示SCN BASE:0002FB37
kcslf kcsgscn_ [380016528, 380016558) = 00000000 0002FB37 00000000 00000000 0000D5E9 00000000 00000000 00000000 00000000 00000000 00000003 80016208
SQL> oradebug dumpvar sga kcsgscn_
00000000 0002FC5C 00000000 00000000 0000D634 00000000 00000000 00000000 00000000 00000000 00000003 80016208
SQL> select to_char(checkpoint_change#,'XXXXXXXX') from v$database;
TO_CHAR(C
    3C264
SQL> select checkpoint_change#  from v$database;
CHECKPOINT_CHANGE#
            246372
1)设置SCN BASE值
0x3C264  8表示修改8个字节的值
BEFORE: [380016528, 380016530) = 00000000 00000000  (mount数据库时kcsgscn_=0)
AFTER:  [380016528, 380016530) = 00000000   -->更改成功

SQL> oradebug dumpvar sga kcsgscn_

SQL> oradebug poke 0x380016528 4 0x00000001   --> 4表示修改前4个字节SCN_WRAP,改成1
AFTER:  [380016528, 38001652C) = 00000001
kcslf kcsgscn_ [380016528, 380016558) = --> 最终SCN_WRAP和SCN_BASE都修改成功
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000003 80016208

SQL> alter database open;
SQL>  select dbms_flashback.get_system_change_number from dual;
GET_SYSTEM_CHANGE_NUMBER
              4295213826 
SQL> select to_char(dbms_flashback.get_system_change_number,'XXXXXXXXXXXXXXXX') from dual;
TO_CHAR(DBMS_FLAS
          --> SCN WRAP跳了一位
SQL>
实际上用poke 地址 8 0x000000010003C264直接修改也可以
SQL> oradebug dumpvar sga kcsgscn_
SQL> select to_char(checkpoint_change#,'XXXXXXXXXXXXXXXX') from v$database;
TO_CHAR(CHECKPOIN
        10003C482 
SQL> oradebug poke 0x380016528 8 0x10003C482
AFTER:  [380016528, 380016530) = 00000001 0003C482
本测试说明大端序64位系统,语法
oradebug poke 地址  8  SCN号
 
 
测试环境2:
linux x86-64
小端序
SQL> select to_char(current_scn,'XXXXXXXX') from v$database;
TO_CHAR(CURRENT_SCN,'XXXXXX
---------------------------
    B49D9
SQL> oradebug dumpvar sga kcsgscn_
kcslf kcsgscn_ [060017008, 060017038) = 000B49DD 00000000 00000000 00000000 000169BF 00000000 00000000 00000000 00000000 00000000 60016CE8 00000000
SQL>
前4字节是SCN BASE:000B49DD 
5~8字节是SCN WRAP:00000000 

SQL> oradebug poke 0x060017008 8 0x000B56C400000001   -->值设为SCN_BASE SCN_WRAP
BEFORE: [060017008, 060017010) = 00000000 00000000
AFTER:  [060017008, 060017010) = 00000001 000B56C4  
SQL> oradebug dumpvar sga kcsgscn_
kcslf kcsgscn_ [060017008, 060017038) = 00000001 000B56C4   -->修改的值不对,前4字节成了SCN_WRAP,后4字节是SCN_BASE
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 60016CE8 00000000
SQL> oradebug poke 0x060017008 8 0x00000001000B56C4   -->重新修改,不考虑大小端,直接写SCN号
BEFORE: [060017008, 060017010) = 00000001 000B56C4
AFTER:  [060017008, 060017010) = 000B56C4 00000001
SQL> oradebug dumpvar sga kcsgscn_
kcslf kcsgscn_ [060017008, 060017038) = 000B56C4 00000001 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 60016CE8 00000000
SQL>

SQL> alter database open;
Database altered.
SQL> select to_char(current_scn,'XXXXXXXXXXXXXXXX') from v$database;
TO_CHAR(CURRENT_SCN,'XXXXXXXXXXXXXXXX')
---------------------------------------------------
        1000B579F  -->SCN_WRAP跳了1位
SQL>
测试说明小端序64位系统,修改SCN的方法也是
oradebug poke 地址  8  SCN号
 
测试环境3:
windows 7 32bit
小端序
前4字节是SCN_WRAP
后4字节是SCN_BASE
SQL> oradebug setmypid
已处理的语句
SQL> oradebug dumpvar sga kcsgscn_
kcslf kcsgscn_ [59852C8, 59852E8) = 00000000 00000000 00000000 00000000 00000000 00000000 00000000 059850C0
SQL>
SQL> select to_char(checkpoint_change#,'XXXXXXXXXXXXXXXX') from v$database;
TO_CHAR(CHECKPOIN
-----------------
            3378B
SQL> oradebug poke 0x59852C8 8 0x000000010003378B  --> 32位系统寻址只能是4字节,不能填8
ORA-00082: 8 的内存大小不在有效集合 [1], [2], [4] 之内
SQL>
SQL>   -->修改SCN_WRAP值
BEFORE: [59852C8, 59852CC) = 00000000
AFTER:  [59852C8, 59852CC) = 00000001
SQL> oradebug poke 0x59852CC 4 0x01
BEFORE: [59852CC, 59852D0) = 00000000
AFTER:  [59852CC, 59852D0) = 00000001
SQL> oradebug dumpvar sga kcsgscn_
kcslf kcsgscn_ [59852C8, 59852E8) = 00000001 00000001 00000000 00000000 00000000 00000000 00000000 059850C0
SQL> oradebug poke 0x59852CC 4 0x0003378B
  --->修改SCN_WRAP值,需要把内存地址+4字节
BEFORE: [59852CC, 59852D0) = 00000001
AFTER:  [59852CC, 59852D0) = 0003378B
SQL>  oradebug dumpvar sga kcsgscn_
kcslf kcsgscn_ [59852C8, 59852E8) =  00000000 00000000 00000000 00000000 00000000 059850C0
SQL>
SQL> alter database open;
数据库已更改。
SQL> select to_char(current_scn,'XXXXXXXXXXXXXXXX') from v$database;
TO_CHAR(CURRENT_S
-----------------
        10003381A
  --> SCN_WRAP跳了1位。
 测试表明对于32位系统,需要分别改SCN_WRAP和SCN_BASE来修改内存中的SCN
posted @ 2020-09-29 23:22  da0h1  阅读(187)  评论(0编辑  收藏  举报