HelloDBA [English]
搜索Internet 搜索 HelloDBABA
  Oracle技术站。email: fuyuncat@gmail.com  MSN: fuyuncat@hotmail.com   acoug  acoug 

偷梁换柱——极端情况下的数据拯救(二)

[English]

作者: fuyuncat

来源: www.HelloDBA.com

日期: 2013-03-20 05:02:15

分享到  新浪微博 腾讯微博 人人网 i贴吧 开心网 豆瓣 淘宝 推特 Facebook GMail Blogger Orkut Google Bookmarks

 这个数据拯救的测试中,环境更加复杂:旧数据库异常关闭;旧数据库仅剩下三个数据文件,其中两个属于系统表空间且文件号不连续,其它文件,诸如控制文件、在线日志文件、UNDO表空间文件、临时表空间及其它数据文件都已丢失。因此在数据恢复过程中也遇到更多的问题。

同样,需要先获得数据库版本、数据库名称和原始的数据文件位置及大小等信息,设置SID和密码。以下为参数文件内容:

SQL代码
  1. _allow_resetlogs_corruption = true  
  2. control_files              = (/opt/oracle/oradata/ORA10R2/control/ora_control1,  
  3.                               /opt/oracle/oradata/ORA10R2/control/ora_control2,  
  4.                               /opt/oracle/oradata/ORA10R2/control/ora_control3)  
  5. db_name                    = ORA10R2  
  6. db_domain                  = ""  
  7. db_block_size              = 8192  
  8. undo_management            = manual  
  9. undo_tablespace            = ''  
  10. UNDO_RETENTION             = 900  
  11. nls_language               = "AMERICAN"  
  12. nls_territory              = "AMERICA"  
  13. user_dump_dest             = /opt/oracle/admin/ORA10R2/udump  
  14. background_dump_dest       = /opt/oracle/admin/ORA10R2/bdump  
  15. core_dump_dest             = /opt/oracle/admin/ORA10R2/cdump  
  16. sga_max_size               = 200M  
  17. sga_target                 = 200M  

然后创建新库:

SQL代码
  1. SQL> CREATE DATABASE ORA10R2  
  2.    USER SYS IDENTIFIED BY oracle  
  3.    USER SYSTEM IDENTIFIED BY oracle  
  4.    LOGFILE GROUP 1 ('/opt/oracle/oradata/ORA10R2/onlinelog/redo01.log'SIZE 20M,  
  5.            GROUP 2 ('/opt/oracle/oradata/ORA10R2/onlinelog/redo02.log'SIZE 20M,  
  6.            GROUP 3 ('/opt/oracle/oradata/ORA10R2/onlinelog/redo03.log'SIZE 20M  
  7.    MAXLOGFILES 5  
  8.    MAXLOGMEMBERS 5  
  9.    MAXLOGHISTORY 1  
  10.    MAXDATAFILES 100  
  11.    MAXINSTANCES 1  
  12.    CHARACTER SET US7ASCII  
  13.    NATIONAL CHARACTER SET AL16UTF16  
  14.    DATAFILE '/opt/oracle/oradata/ORA10R2/datafile/ORA10R2_system_200m' SIZE 180M REUSE  
  15.    --, '/opt/oracle/oradata/ORA10R2/datafile/ORA10R2_system_02' SIZE 200M REUSE  
  16.    EXTENT MANAGEMENT LOCAL  
  17.    SYSAUX DATAFILE '/opt/oracle/oradata/ORA10R2/datafile/sysaux01' SIZE 100M  
  18.    DEFAULT TEMPORARY TABLESPACE tempts1  
  19.       TEMPFILE '/opt/oracle/oradata/ORA10R2/datafile/temp01' SIZE 20M  
  20.    --UNDO TABLESPACE undotbs1  
  21.    --   DATAFILE '/opt/oracle/oradata/ORA10R2/datafile/undotbs01'  
  22.    --   SIZE 500M AUTOEXTEND ON NEXT 5120K MAXSIZE UNLIMITED  
  23.    ;  
  24.   
  25.   2    3    4    5    6    7    8    9   10   11   12   13   14   15   16   17  18   19   20   21   22   23  
  26. Database created.  

因为我们旧的系统表空间中有两个不连续的数据文件,因此我们需要想办法创建出相应文件号的数据文件。

首先,我们用BBED可以看到第二个数据文件的文件号:

SQL代码
  1. BBED> p kcvfh  
  2. ...  
  3.       ub2 kccfhfno                          @52       0x0008  
  4. ...  

为了让新的系统文件号为8,我们需要创建几个临时的数据文件提高文件号,然后再添加新的系统文件:

SQL代码
  1. SQL> create tablespace test datafile '/opt/oracle/oradata/ORA10R2/datafile/test3' size 10M, '/opt/oracle/oradata/ORA10R2/datafile/test4' size 10M, '/opt/oracle/oradata/ORA10R2/datafile/test5' size 10M, '/opt/oracle/oradata/ORA10R2/datafile/test6' size 10M, '/opt/oracle/oradata/ORA10R2/datafile/test7' size 10M;  
  2. alter tablespace system add datafile '/opt/oracle/oradata/ORA10R2/datafile/ORA10R2_system_02' size 200M;  
  3. DROP TABLESPACE test INCLUDING CONTENTS AND DATAFILES;  
  4.   
  5. Tablespace created.  
  6.   
  7. SQL>  
  8. Tablespace altered.  
  9.   
  10. SQL>  
  11. Tablespace dropped.  

如果这里我们按照之前11g的过程继续操作,将会遇到大量错误,诸如ORA-00600 [4000], ORA-01555, ORA-01111, ORA-01173, ORA-00600 [4049]等等。经过深入分析,发现导致这些错误的最终原因是:一致性读。

因为新库创建后,其Checkpoint SCN非常小,因此在Bootstrap过程中读取系统数据字典数据块时,与数据块上的ITL中scn比较,发现需要进行一致性回滚,因而会读取回滚段数据,但这些回滚段通常都是不存在,因此会导致以上诸多错误的出现。

当然,这也产生了一个疑问:为什么在11g的恢复过程没有发生这些问题?通过对比发现,在11g的恢复过程中,NID操作重新设置了系统文件中的Checkpoint SCN,使其恢复为其原来的SCN。因为我们已经将其文件头替换为新文件的文件头,因此我猜测NID过程中读取了数据字典中SCN信息,并重写的文件头。从nid过程抛出的ORA-00600错误也可以看到,它调用了系统的内部包完成ID修改过程。

但在10g的NID过程,并没有修改SCN,因此需要我们手动提高SCN。这里,我使用了隐含参数_minimum_giga_scn。设置该参数,我们需要观察alert log,因为数值太小不会成功,日志中出现以下记录

SQL代码
  1. Current SCN is not changed: _minimum_giga_scn (scn 274877906944) is too small  

我们这里设置_minimum_giga_scn = 1024,重启数据库,alert日志提示设置成功

SQL代码
  1. Advancing SCN to 1099511627776 according to _minimum_giga_scn  

接下来重命名新系统文件,拷贝旧数据文件到当前数据文件目录:

SQL代码
  1. [oracle@server1 ORA10R2]$ mv datafile/ORA10R2_system_200m datafile/ORA10R2_system_200m_new  
  2. [oracle@server1 ORA10R2]$ mv datafile/ORA10R2_system_02 datafile/ORA10R2_system_02_new  
  3. [oracle@server1 ORA10R2]$ cp ../ORA10R2_COPY/datafile/ORA10R2_system_200m ./datafile/  
  4. [oracle@server1 ORA10R2]$ cp ../ORA10R2_COPY/datafile/ORA10R2_system_02 ./datafile/  
  5. [oracle@server1 ORA10R2]$ cp ../ORA10R2_COPY/datafile/ORA10R2_example_50m ./datafile/  

然后执行nid修改数据库ID(不过我认为这一步在这里已经不重要了):

SQL代码
  1. [oracle@server1 ORA10R2]$ nid target=sys/oracle  
  2.   
  3. DBNEWID: Release 10.2.0.1.0 - Production on Tue Mar 19 00:44:33 2013  
  4. ... ...  
  5. Database ID for database ORA10R2 changed to 4153675250.  
  6. All previous backups and archived redo logs for this database are unusable.  
  7. Database has been shutdown, open database with RESETLOGS option.  
  8. Succesfully changed database ID.  
  9. DBNEWID - Completed succesfully.  

重建控制文件,并恢复、OPEN RESETLOGS:

SQL代码
  1. SQL> CREATE CONTROLFILE REUSE DATABASE ORA10R2 RESETLOGS NOARCHIVELOG  
  2.     MAXLOGFILES 5  
  3.     MAXLOGMEMBERS 5  
  4.     MAXDATAFILES 100  
  5.     MAXINSTANCES 1  
  6.     MAXLOGHISTORY 292  
  7. LOGFILE  
  8.   GROUP 1 '/opt/oracle/oradata/ORA10R2/onlinelog/redo01.log' SIZE 20M,  
  9.   GROUP 2 '/opt/oracle/oradata/ORA10R2/onlinelog/redo02.log' SIZE 20M,  
  10.   GROUP 3 '/opt/oracle/oradata/ORA10R2/onlinelog/redo03.log' SIZE 20M  
  11. DATAFILE  
  12.   '/opt/oracle/oradata/ORA10R2/datafile/ORA10R2_system_200m' SIZE 180M  
  13.   , '/opt/oracle/oradata/ORA10R2/datafile/ORA10R2_system_02' SIZE 200M  
  14.   --, '/opt/oracle/oradata/ORA10R2/datafile/sysaux01' size 100M  
  15.   --, '/opt/oracle/oradata/ORA10R2/datafile/undotbs01'  
  16. CHARACTER SET US7ASCII  
  17. ;  
  18.   2    3    4    5    6    7    8    9   10   11   12   13   14   15   16   17  
  19. Control file created.  
  20.   
  21. SQL> recover database using backup controlfile until cancel;  
  22. ORA-00279: change 1099511627897 generated at 03/19/2013 00:43:31 needed for  
  23. thread 1  
  24. ORA-00289: suggestion : /opt/oracle/product/10.2.0/db/dbs/arch1_2_810434521.dbf  
  25. ORA-00280: change 1099511627897 for thread 1 is in sequence #2  
  26.   
  27.   
  28. Specify log: {<RET>=suggested | filename | AUTO | CANCEL}  
  29. cancel  
  30. Media recovery cancelled.  
  31. SQL> alter database open resetlogs;  
  32. alter database open resetlogs  
  33. *  
  34. ERROR at line 1:  
  35. ORA-01092: ORACLE instance terminated. Disconnection forced  

数据库打开失败,从alert日志看到错误内容为:

SQL代码
  1. ORA-01177: data file does not match dictionary - probably old incarnation  
  2. ORA-01110: data file 1: '/opt/oracle/oradata/ORA10R2/datafile/ORA10R2_system_200m'  

再次执行恢复和打开过程,并启动10046事件跟踪,从跟踪内容中看到引起该错误的语句及等待事件:

SQL代码
  1. PARSING IN CURSOR #2 len=122 dep=1 uid=0 oct=3 lid=0 tim=1331710783410619 hv=1330125001 ad='2c3341c8'  
  2. select blocks,NVL(ts#,-1),status$,NVL(relfile#,0),maxextend,inc, crscnwrp,crscnbas,NVL(spare1,0) from file$ where file#=:1  
  3. END OF STMT  
  4. PARSE #2:c=0,e=300,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,tim=1331710783410615  
  5. BINDS #2:  
  6. kkscoacd  
  7.  Bind#0  
  8.   oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00  
  9.   oacflg=08 fl2=0001 frm=00 csi=00 siz=24 off=0  
  10.   kxsbbbfp=b71e3928  bln=22  avl=02  flg=05  
  11.   value=1  
  12. EXEC #2:c=1000,e=574,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,tim=1331710783411304  
  13. WAIT #2: nam='db file sequential read' ela= 14 file#=1 block#=258 blocks=1 obj#=-1 tim=1331710783411361  
  14. WAIT #2: nam='db file sequential read' ela= 10 file#=1 block#=114 blocks=1 obj#=-1 tim=1331710783411419  
  15. ...  
  16. ORA-01177: data file does not match dictionary - probably old incarnation  
  17. ORA-01110: data file 1: '/opt/oracle/oradata/ORA10R2/datafile/ORA10R2_system_200m'  

显然,启动进程读取了数据字典file$的数据(第114块数据块),再与数据文件头中的信息对比,存在不匹配数据,则抛出1777错误。

处理1777错误前,我们启动致mount状态,并做文件恢复

SQL代码
  1. SQL> startup mount  
  2. SQL> recover datafile 1  
  3. Media recovery complete.  
  4. SQL> recover datafile 8  
  5. Media recovery complete.  

用bbed打开114号数据块,即file$的数据块,查看第一条记录,即文件1的数据

SQL代码
  1. BBED> set file 1 block 114  
  2.         FILE#           1  
  3.         BLOCK#          114  
  4. BBED> p *kdbr[0]  
  5. BBED> x /rnnnnnnnnnnnnnnnnnnnnnnnnnnn  
  6. rowdata[678]                                @8153  
  7. ------------  
  8. flag@8153: 0x2c (KDRHFL, KDRHFF, KDRHFH)  
  9. lock@8154: 0x00  
  10. cols@8155:   11  
  11.   
  12. col    0[2] @8156: 1 -- FILE#  
  13. col    1[2] @8159: 2 -- STATUS$  
  14. col    2[4] @8162: 23040 -- BLOCKS  
  15. col    3[1] @8167: 0 -- TS#  
  16. col    4[2] @8169: 1 -- RELFILE#  
  17. col    5[1] @8172: 0 -- MAXEXTEND  
  18. col    6[1] @8174: 0 -- INC  
  19. col    7[1] @8176: 0 -- CRSCNWRP  
  20. col    8[2] @8178: 8 -- CRSCNBAS  
  21. col    9[0] @8181: *NULL-- OWNERINSTANCE  
  22. col   10[5] @8182: 4194306 -- SPARE1  

再打开文件头,可以发现create scn(CRSCNWRP, CRSCNBAS)不匹配

SQL代码
  1. BBED> set file 1 block 1  
  2. BBED> map  
  3. BBED> p kcvfh  
  4. struct kcvfh, 676 bytes                     @0  
  5.    struct kcvfhbfh, 20 bytes                @0  
  6.       ub1 type_kcbh                         @0        0x0b  
  7.       ub1 frmt_kcbh                         @1        0xa2  
  8.       ub1 spare1_kcbh                       @2        0x00  
  9. ...  
  10.    struct kcvfhcrs, 8 bytes                 @100  
  11.       ub4 kscnbas                           @100      0x00000006  -- CRSCNBAS  
  12.       ub2 kscnwrp                           @104      0x0000      -- CRSCNWRP  
  13. ...  
  14.    struct kcvfhckp, 36 bytes                @484  
  15.       struct kcvcpscn, 8 bytes              @484  
  16.          ub4 kscnbas                        @484      0x00006fa4  -- CKPCNBAS  
  17.          ub2 kscnwrp                        @488      0x0100      -- CKPCNWRP  
  18. ...   

要规避这个问题,就需要时数据字典中的数据与文件头中的信息一致。这里我修改了数据字典当中的数据

用dump函数看我们需要写入什么数据:

SQL代码
  1. SQL> select dump(6,16) from dual;  
  2.   
  3. DUMP(8,16)  
  4. -----------------  
  5. Typ=2 Len=2: c1,7  

然后用BBED修改该记录:

SQL代码
  1. BBED> set file 1 block 114  
  2. BBED> dump offset 8178 count 4  
  3. BBED> modify /x 02c107ff  
  4. BBED> sum apply  

接下来避免8号文件出现同样错误,同样修改其记录。

8号文件头数据:

SQL代码
  1. struct kcvfhcrs, 8 bytes                 @100  
  2.   ub4 kscnbas                           @100      0x00001c64  
  3.   ub2 kscnwrp                           @104      0x0000  

数据字典数据:

SQL代码
  1. col    0[2] @7478: 8  
  2. col    1[2] @7481: 2  
  3. col    2[3] @7484: 25600  
  4. col    3[1] @7488: 0  
  5. col    4[2] @7490: 8  
  6. col    5[1] @7493: 0  
  7. col    6[1] @7495: 0  
  8. col    7[1] @7497: 0  
  9. col    8[4] @7499: 140113  
  10. col    9[0] @7504: *NULL*  
  11. col   10[5] @7505: 33554434  

Dump结果:

SQL代码
  1. SQL> select dump(7268,16) from dual;  
  2.   
  3. DUMP(7268,16)  
  4. ---------------------  
  5. Typ=2 Len=3: c2,49,45  
  6.   
  7. SQL> select dump(140113,16) from dual;  
  8.   
  9. DUMP(140113,16)  
  10. ---------------------  
  11. Typ=2 Len=4: c3,f,2,e  

再用BBED修改

SQL代码
  1. BBED> dump offset 7499 count 6  
  2. BBED> modify /x 04c24945  
  3. BBED> sum apply  

修改完成后,开启数据库成功,并读取出旧数据库中数据字典内容:

SQL代码
  1. SQL> alter database open;  
  2.   
  3. Database altered.  
  4.   
  5. SQL> select file_id, tablespace_name from dba_data_files where tablespace_name like '%EXAMPLE%';  
  6.   
  7.    FILE_ID TABLESPACE_NAME  
  8. ---------- ------------------------------  
  9.          4 EXAMPLE  
  10.   
  11. SQL> select file#, name from v$datafile where file#=4;  
  12.   
  13.      FILE# NAME  
  14. ---------- --------------------------------------------------------------------------------  
  15.          4 /opt/oracle/product/10.2.0/db/dbs/MISSING00004  

重命名数据文件:

SQL代码
  1. SQL> ALTER DATABASE RENAME FILE '/opt/oracle/product/10.2.0/db/dbs/MISSING00004' TO '/opt/oracle/oradata/ORA10R2/datafile/ORA10R2_example_50m';  
  2.   
  3. Database altered.  

重新恢复数据库,使数据文件ONLINE:

SQL代码
  1. SQL> shutdown  
  2. ... ...  
  3. SQL> recover database until cancel;  
  4. Media recovery complete.  
  5. SQL> ALTER DATABASE DATAFILE '/opt/oracle/oradata/ORA10R2/datafile/ORA10R2_example_50m' ONLINE;  
  6.   
  7. Database altered.  
  8.   
  9. SQL> alter database open resetlogs;  
  10. alter database open resetlogs  
  11. *  
  12. ERROR at line 1:  
  13. ORA-01122: database file 4 failed verification check  
  14. ORA-01110: data file 4: '/opt/oracle/oradata/ORA10R2/datafile/ORA10R2_example_50m'  
  15. ORA-01206: file is not part of this database - wrong database id  

在打开数据库时,抛错,指示加入的数据文件的数据库ID不匹配。

通过其他文件可以看到当前数据库的DBID:

SQL代码
  1. BBED> set file 1 block 1  
  2.         FILE#           1  
  3.         BLOCK#          1  
  4.   
  5. BBED> p kcvfh  
  6. ...   
  7.       ub4 kccfhdbi                          @28       0xf7940df2  
  8. ...  
  9. BBED> dump offset 28 count 4  
  10.  File: /opt/oracle/oradata/ORA10R2/datafile/ORA10R2_system_200m (1)  
  11.  Block: 1                Offsets:   28 to   31           Dba:0x00400001  
  12. ------------------------------------------------------------------------  
  13.  f20d94f7  

通过BBED修改ID:

SQL代码
  1. BBED> set file 4 block 1  
  2.         FILE#           4  
  3.         BLOCK#          1  
  4.   
  5. BBED> p kcvfh  
  6. ...  
  7.       ub4 kccfhdbi                          @28       0xb9888c45  
  8. ...  
  9. BBED> dump offset 30 count 2  
  10.  File: /opt/oracle/oradata/ORA10R2/datafile/ORA10R2_example_50m (4)  
  11.  Block: 1                Offsets:   30 to   31           Dba:0x01000001  
  12. ------------------------------------------------------------------------  
  13.  88b9  
  14. BBED> modify /x 94f7  
  15.  File: /opt/oracle/oradata/ORA10R2/datafile/ORA10R2_example_50m (4)  
  16.  Block: 1                Offsets:   30 to   31           Dba:0x01000001  
  17. ------------------------------------------------------------------------  
  18.  94f7  
  19. BBED> dump offset 28 count 4  
  20.  File: /opt/oracle/oradata/ORA10R2/datafile/ORA10R2_example_50m (4)  
  21.  Block: 1                Offsets:   28 to   31           Dba:0x01000001  
  22. ------------------------------------------------------------------------  
  23.  f29d94f7  
  24. BBED> modify /x f20d  
  25.  File: /opt/oracle/oradata/ORA10R2/datafile/ORA10R2_example_50m (4)  
  26.  Block: 1                Offsets:   28 to   31           Dba:0x01000001  
  27. ------------------------------------------------------------------------  
  28.  f20d94f7  
  29.   
  30. BBED> sum apply  
  31. Check value for File 4, Block 1:  
  32. current = 0x4460, required = 0x4460  

再次启动,成功!

SQL代码
  1. SQL> alter database open resetlogs;  
  2.   
  3. Database altered.  

创建临时表空间,修改用户:

SQL代码
  1. SQL> CREATE TEMPORARY TABLESPACE temp2 TEMPFILE '/opt/oracle/oradata/ORA10R2/datafile/temp02' size 100M;  
  2.   
  3. Tablespace created.  
  4.   
  5. SQL> select 'ALTER USER '||username||' TEMPORARY TABLESPACE TEMP2;' from dba_users;  
  6.   
  7. 'ALTERUSER'||USERNAME||'TEMPORARYTABLESPACETEMP2;'  
  8. ---------------------------------------------------------------------  
  9. ALTER USER STMADMIN TEMPORARY TABLESPACE TEMP2;  
  10. ... ...  
  11.   
  12. SQL> ALTER USER STMADMIN TEMPORARY TABLESPACE TEMP2;  
  13. ... ...  
  14. User altered.  

用EXP导出数据:

SQL代码
  1. [oracle@server1 ORA10R2]$ exp system/oracle tablespaces=EXAMPLE file=resecue.dat log=resecue.log  
  2. ... ...  
  3. . . exporting table                         USR_MV         11 rows exported  
  4. . exporting referential integrity constraints  
  5. . exporting triggers  
  6. Export terminated successfully without warnings.  

数据已经成功拯救出来。

不过,这两个测试都是在实验环境当中的,实际情况可能更为复杂。这个恢复方法只能视为一根救命稻草,真正能保证数据安全的还是完善的备份计划和容灾方案。

--- Fuyuncat ---

Top

Copyright ©2005,HelloDBA.Com 保留一切权利

申明
by fuyuncat