Oracle Block Corruption的检测与处理

博客首页 » Oracle Block Corruption的检测与处理

发布于 20 Nov 2013 01:47
标签 blog
Oracle Database Block Corruption的检测与处理

坏块的检测

DBVerify

http://blog.csdn.net/tianlesoftware/article/details/5015164

Oracle DBV 工具 说明
分类: Oracle Advanced Knowledge 2009-12-16 00:35 5019人阅读 评论(0) 收藏 举报
oraclefileheaderdatabase数据库工具
目录(?)[+]


一. DBV 说明
DBV是一个常用的工具,OracleMOS上有一篇文章介绍DBV:[ID 35512.1]。

dbverify工具的主要目的是为了检查数据文件的物理结构,包括数据文件是否损坏,是否存在逻辑坏块,以及数据文件中包含何种类型的数据。

DBV checks Oracledatafiles to ensure that:
(1)The datafile has a valid header
(2)Each datablock in the file has aspecial "wrapper" which identifies the block - this"wrapper" is checked for correctness
(3)DATA (TABLE) and INDEX blocks areinternally consistent
(4)From 8.1.6 onwards: That variousother block types are internally consistent (such as rollback segmentblocks)

The tool can be used to give some degree of confidence that a datafile is free fromcorruption. It opens files in a read only mode and so cannot change thecontents of the file being checked.

DBVERIFY工具可以验证ONLINE或OFFLINE的数据文件。不管数据库是否打开,都可以访问数据文件。

注意:
(1)对于DBVERIFY工具,高版本可以自动识别低版本数据库,比如11g的dbv访问9i的数据库,但是低版本的dbv访问高版本会报如下之类的错误:
DBVERIFY-验证正在开始: FILE =e:/oracle/oradata/Dave/test01.dbf
汇入的页1 -可能是介质损坏
(2)查看数据坏块所在数据文件号及块号可以对表进行一次全表扫描,如:
select count(*) from tablename;
如果有坏块, 在扫描的时候就会报错。

二. dbv的命令参数
C:/>dbv help=y
DBVERIFY: Release 11.1.0.7.0 - Productionon 星期二 12月 15 23:35:24 2009
Copyright (c) 1982, 2007, Oracle. Allrights reserved.
关键字 说明 (默认值)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FILE 要验证的文件 (无)
START 起始块 (文件的第一个块)
END 结束块 (文件的最后一个块)
BLOCKSIZE 逻辑块大小 (8192)
LOGFILE 输出日志 (无)
FEEDBACK 显示进度 (0)
PARFILE 参数文件 (无)
USERID 用户名/口令 (无)
SEGMENT_ID 段 ID (tsn.relfile.block) (无)
HIGH_SCN 要验证的最高块 SCN (无)
(scn_wrap.scn_base 或 scn)

(1)FILE(File to Verify):This is the name of the file to verify. See"Limitations" below if your datafile name has no suffix.
(2)START(Start Block):This is the first datablock to check in the file.This defaults to the first block in the file and need only be specifiedif you want to check just a portion of a given file.
(3)END(End Block):This is the last datablock to check in the file. Thisdefaults to the last block of the filebut may need specifying for RAW devices(See "Limitations" below) BLOCKSIZE Logical Block Size This is the database blocksize of the datafile you wish to scan. The value defaults to "2048". Thisparameter must be set to the DB_BLOCK_SIZE of the datafile to be scanned.
(4)LOGFILE(Output Log):This is the name of file to outputthe results to. The default is "NONE" and output is sent to terminal.
(5)FEEDBACK( Display Progress): If set to a value above 0 (the default) then DBVoutputs a "." for every N pages of the datafile checked. This isuseful to see that DBV is working through the ile.
(6)PARFILE(Parameter file):Parameters can be specified in a parameterfile and PARFILE used to cause the filecontents to be used as input parameters. The PARFILE can contain any of theabove options.
(7)HIGH_SCN(Scn):Highest Block SCN To Verify (scn_wrap.scn_base OR scn) Find theblocks exceeding the SCN. Available in version 9.2.0.6 and above.
(8)USERID (Username/Password):If the file you are verifying isan Automatic Storage Management (ASM) file, you must supply a USERID. This isbecause DBVERIFY needs to connect to an Oracle instance to access ASM files.
(9)SEGMENT_ID (TS#.FILE#.BLOCK#):Specifies the segment that youwant to verify. For more info, review Note:139962.1

三. DBV 限制
3.1 As DBV performs checks at a block levelit cannot detect problems such as INDEX versus TABLE mismatches which can bedetected by the 'ANALYZE TABLE .. VALIDATE STRUCTURE CASCADE' command.

3.2 This utility can ONLY be used against DATAfiles. It CANNOT be used to verify redolog files or control files.

3.3 You can use DBV to verify an AutomaticStorage Management (ASM) file.
However, the database must be opened and the option USERID has to beused

Example : dbv file=+DG1/ORCL/datafile/system01.dbf userid=system/sys

DBV checks the userid/password for ASM managed files, which is notpossible when database is not open.

3.4 On most releases on Unix DBV expects afilename extension.
This means that DBV cannot be used against datafiles with no filenamesuffix, or against RAW devices. - - DBV 要求datafile 必须有扩展名
The workaround is to create a symbolic link to the raw device where thelink name MUST have an extension.
Eg: ln -s /dev/rdsk/mydevice /tmp/mydevice.dbf
Now use DBV against /tmp/mydevice.dbf
- - 如果裸设备没有扩展名,可以创建一个link,然后在进行dbv 检查。

3.5 For RAW devices you should use the ENDparameter to avoid running off the end of the Oracle file space.
eg: "dbv FILE=/dev/rdsk/r1.dbf END=<last_block_number>"
Ifyou get the END value too high DBV can report the last page/s of the file ascorrupt as these are beyond the end of the Oracle portion of the raw device.

You can find value for END from the V$DATAFILE view by dividing the BYTESvalue by the database block size.

Eg: To find out the END value to use for file#=5:
SVRMGRL> show parameter db_block_size
NAME TYPE VALUE
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
db_block_size integer 2048

SVRMGRL> select BYTES/2048 from v$datafile where FILE#=5;
BYTES/2048
- - - - - - - - - -
5120

So the command would be:
dbvfile=/dev/rdsk/r1.dbf blocksize=2048 END=5120
- - SVRMGRL 命令在oracle 10g已经取消,并且db_block_size 默认值也变成了8k。

3.6 DBV may not be able to scan datafileslarger than 2Gb and may report "DBV-100". This is reported in Bug:710888for Unix and Bug:1372172for 8.1.6 on NT. This problem is platform and release specific so if you getDBV-100 errors check the filesize first.

3.7 DBV from 8.1.6 onwards may reportspurious errors for rollback segment blocks if the database has been migratedfrom Oracle7. See Bug:1359160and Note:118008.1.

3.8 DBV only checks a block in isolation -it does not know if the block is part of an existing object or not.

3.9 DBV is broken on SCO Unix - see Bug:814249

3.10 DBV of a lower version should not beused against a higher DB version.


四. DBV 示例

4.1 验证ASM 上的文件
SYS@anqing2(rac2)> select file_name fromdba_data_Files;
FILE_NAME
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+DATA/anqing/datafile/users.273.751548233
+DATA/anqing/datafile/sysaux01.dbf
+DATA/anqing/datafile/undotbs01.dbf
+DATA/anqing/datafile/system01.dbf
+DATA/anqing/datafile/system02.dbf
+DATA/anqing/datafile/undotbs02.dbf
+DATA/anqing/datafile/dave01.dbf
+DATA/anqing/datafile/test01.dbf

- - dbv check ASM 上的文件,注意添加userid参数
[oracle@rac2 ~]$ dbvfile='+DATA/anqing/datafile/undotbs02.dbf' userid=sys/oracle

DBVERIFY: Release 10.2.0.4.0 - Productionon Tue Aug 9 21:44:36 2011

Copyright (c) 1982, 2007, Oracle. All rights reserved.

DBVERIFY - Verification starting : FILE =+DATA/anqing/datafile/undotbs02.dbf

DBVERIFY - Verification complete

Total Pages Examined : 64000
Total Pages Processed (Data) : 0
Total Pages Failing (Data) : 0
Total Pages Processed (Index): 0
Total Pages Failing (Index): 0
Total Pages Processed (Other): 32748
Total Pages Processed (Seg) : 0
Total Pages Failing (Seg) : 0
Total Pages Empty : 31252
Total Pages Marked Corrupt : 0
Total Pages Influx : 0
Highest block SCN : 0 (0.0)

4.2 验证普通datafile
- - 实例没有启动的情况下进行datafile 验证
D:\app\Administrator\oradata\newccs>dbvfile=undotbs01.dbf

DBVERIFY: Release 11.2.0.1.0 - Productionon Tue Aug 9 21:52:41 2011

Copyright (c) 1982, 2009, Oracle and/or itsaffiliates. All rights reserved.

DBVERIFY - Verification starting : FILE =D:\APP\ADMINISTRATOR\ORADATA\NEWCCS\UNDOTBS01.DBF

DBVERIFY - Verification complete

Total Pages Examined : 64000
Total Pages Processed (Data) : 0
Total Pages Failing (Data) : 0
Total Pages Processed (Index): 0
Total Pages Failing (Index): 0
Total Pages Processed (Other): 35199
Total Pages Processed (Seg) : 10
Total Pages Failing (Seg) : 0
Total Pages Empty : 28801
Total Pages Marked Corrupt : 0
Total Pages Influx : 0
Total Pages Encrypted : 0
Highest block SCN : 1315907818 (0.1315907818)

- - 这种情况下,db没有启动,要进入数据文件的存放目录后在运行该命令,不然会报找不到数据文件。

4.3 DB open 状态,验证指定段
命令格式如下:
dbv USERID=username/passwordSEGMENT_ID=tsn.relfile.block

可以通过sys_dba_segs表获取tablespace_id,header_file, header_block三个字段,他们分别对应tsn,relfile,block.

SYS@anqing2(rac2)> select tablespace_id,header_file, header_block from sys_dba_segs where segment_name = 'TA';

TABLESPACE_ID HEADER_FILE HEADER_BLOCK
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
0 1 71513

[oracle@rac2 ~]$ dbv segment_id=0.1.71513 userid=sys/oracle

DBVERIFY: Release 10.2.0.4.0 - Productionon Tue Aug 9 21:59:32 2011

Copyright (c) 1982, 2007, Oracle. All rights reserved.


DBV-00111: OCI failure(1913) (ORA-28009: connection as SYS should be as SYSDBA or SYSOPER
)
[oracle@rac2 ~]$ dbvsegment_id=0.1.71513 userid=system/oracle

DBVERIFY: Release 10.2.0.4.0 - Productionon Tue Aug 9 21:59:46 2011

Copyright (c) 1982, 2007, Oracle. All rights reserved.

DBVERIFY - Verification starting :SEGMENT_ID = 0.1.71513


DBVERIFY - Verification complete

Total Pages Examined : 2281
Total Pages Processed (Data) : 2280
Total Pages Failing (Data) : 0
Total Pages Processed (Index): 0
Total Pages Failing (Index): 0
Total Pages Processed (Other): 0
Total Pages Processed (Seg) : 1
Total Pages Failing (Seg) : 0
Total Pages Empty : 0
Total Pages Marked Corrupt : 0
Total Pages Influx : 0
Highest block SCN : 0 (0.0)
[oracle@rac2 ~]$

注:这种方式要求数据库处于打开的状态。

4.4 验证数据拷贝
由于dbv可以在实例关闭情况下验证数据文件,因此dbv也可以验证数据文件的拷贝。这个拷贝指的是通过RMAN的COPY命令或者操作系统命令cp拷贝的数据文件,而不是RMAN生成的备份集格式。

如:
E:/app/Administrator/oradata/orcl>dbvfile= USERS01bak.DBF blocksize=8192
DBVERIFY: Release 11.1.0.7.0 - Productionon 星期三 12月 16 00:30:17 2009
Copyright (c) 1982, 2007, Oracle. Allrights reserved.
DBVERIFY - 开始验证: FILE = E:/app/Administrator/oradata/orcl/USERS01bak.DBF
DBVERIFY - 验证完成
检查的页总数: 640
处理的页总数 (数据): 91
失败的页总数 (数据): 0
处理的页总数 (索引): 33
失败的页总数 (索引): 0
处理的页总数 (其它): 496
处理的总页数 (段) : 0
失败的总页数 (段) : 0
空的页总数: 20
标记为损坏的总页数: 0
流入的页总数: 0
加密的总页数 : 0
最高块 SCN :904088 (0.904088)

通过比较2个dbv 的结果来比较datafile 的copy




- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Blog: http://blog.csdn.net/tianlesoftware
Weibo: http://weibo.com/tianlesoftware
Email: moc.liamg|abd.dvd#moc.liamg|abd.dvd
DBA1 群:62697716(满); DBA2 群:62697977(满) DBA3 群:62697850(满)
DBA 超级群:63306533(满); DBA4 群: 83829929(满) DBA5群: 142216823(满)
DBA6 群:158654907(满) 聊天 群:40132017(满) 聊天2群:69087192(满)
- - 加群需要在备注说明Oracle表空间和数据文件的关系,否则拒绝申请

DB_CHECK_SUM init parameter
RMAN BACKUP VALIDATE

Official Manual
http://docs.oracle.com/cd/B19306_01/backup.102/b14194/rcmsynta009.htm#RCMRF107

http://www.alixixi.com/program/a/2008020940790.shtml

12. Corruption detection
RMAN可以备份包含损坏数据块的数据文件,查询视图V$BACK_CORRUPTION和V$COPY_CORRUPTION可以获得有关坏数据的信息。

通过设置 set maxcorrupt 可以跳过指定个数的坏块来避免备份失败。

RMAN> replace script backup_db_full {
2> # Performs a complete backup
3> execute script alloc_disk;
4> set maxcorrupt for datafile 1 to 0;
5> backup
6> …..
7> execute script rel_disk;
8> }

http://blog.csdn.net/tianlesoftware/article/details/5015164

Oracle数据块损坏恢复总结

http://www.cnblogs.com/rootq/archive/2010/11/05/1869876.html

在恢复前使用DBV命令检查数据文件是否存在坏块
dbv file=d:\oracle\oradata\mydb\RONLY.DBF blocksize=8192

查看数据坏块所在数据文件号及块号可以对表进行一次全表扫描,如:
select count(*) from tablename;

1、 没有备份的情况下:
1.1、使用exp/imp恢复

在这种情况下肯定会造成数据的丢失,在这种情况下应采取将数据导出然后重建表再进行导入的方法,来尽量恢复损坏数据块中的数据,但是在有坏块的情况下是不允许导出的,如下命令:
Exp test/test file=t.dmp tables=t;
导出命令在执行中会报ORA-01578错误,在这错误提示中会提示那个文件号的文件以及这个文件中的哪个块被损坏,如:ORA—01578:ORACLE 数据块损坏(文件号 4,块号 35)
针对以上的提示首先查询那些对象被损坏:
Select tablespace_name,segment_type,owner,segment_name From dba_extents Where file_id=4 and 35 between block_id and block_id+blocks-1;
如果被损坏的块是索引,通常可以通过索引重建来解决,如果损坏的是数据(segment_type为table),那么通过设置如下内部事件使得Exp操作跳过坏块。
Alter session set events=’10231 trace name context forever,level 10’;
然后重新执行导出命令,导出相关的表,然后执行Drop Table命令删除相关表,之后重建表最后导入数据。

1.2、使用DBMS_REPAIR恢复

用DBMS_REPAIR当然也会丢失数据。这里不做详细的介绍,有兴趣的可以查看oracle的在线文档

这里,有一篇杨挺昆的文章:

http://yangtingkun.itpub.net/post/468/9121

DBMS_REPAIR的使用
Oracle提供了DBMS_REPAIR包用来发现、标识并修改数据文件中的坏块。

任何工具都不是万能的,使用这个包的同时会带来数据丢失、表和索引返回数据不一致,完整性约束破坏等其他问题。因此当出现错误时,应当首先从物理备份或逻辑备份恢复,使用dbms_repair只是在没有备份的情况下使用的一种手段,这种方式一般都会造成数据的丢失。

dbms_repair包的工作原理比较简单,是将检查到的坏块标注出来,使随后的dml操作跳过该块,同时,dbms_repair包还提供了用于保存索引中包含的标注为坏块中的键值,以及修复freelist和segment bitmap的过程。

有一点需要注意,dbms_repair包没有进行授权,只有sys用户可以执行。

下面通过一个例子来简要介绍一下dbms_repair包的使用。

一、构造测试环境

首先建立一个测试用表空间,由于需要用UtralEdit打开数据文件修改部分内容来模拟错误,因此数据文件要建的小一些。

SQL> CREATE TABLESPACE TEST DATAFILE 'E:ORACLEORADATATESTTEST.DBF' SIZE 1M
2 EXTENT MANAGEMENT LOCAL AUTOALLOCATE SEGMENT SPACE MANAGEMENT MANUAL;

表空间已创建。

SQL> CREATE TABLE TEST (ID NUMBER, NAME VARCHAR2(30)) TABLESPACE TEST;

表已创建。

SQL> INSERT INTO TEST SELECT ROWNUM, OBJECT_NAME FROM DBA_OBJECTS;

已创建6232行。

SQL> COMMIT;

提交完成。

SQL> CREATE INDEX IND_TEST_ID ON TEST (ID);

索引已创建。

SQL> CREATE INDEX IND_TEST_NAME ON TEST (NAME);

索引已创建。

为了确保oracle已经把刚才插入的数据写到数据文件中,现在重起数据库。

SQL> CONN /@TEST AS SYSDBA
已连接。
SQL> SHUTDOWN
数据库已经关闭。
已经卸载数据库。
ORACLE 例程已经关闭。
SQL> STARTUP
ORACLE 例程已经启动。

Total System Global Area 89201304 bytes
Fixed Size 453272 bytes
Variable Size 62914560 bytes
Database Buffers 25165824 bytes
Redo Buffers 667648 bytes
数据库装载完毕。
数据库已经打开。

二、模拟错误的产生

用UtralEdit打开数据文件,只要修改了数据文件中任意的一个位置,都会造成数据文件错误。但我们测试需要将错误发生位置定位在TEST表中。

SQL> CONN YANGTK/YANGTK@TEST
已连接。

SQL> SELECT SUBSTR(ROWID, 10, 6), ID, NAME FROM TEST WHERE ID = 123;

SUBSTR(ROWID ID NAME
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AAAAAG 123 ALL_REPCONFLICT

如何在数据文件中找到TEST表的数据呢?可以通过ROWID来定位的记录在数据文件中的位置。任意选择一条记录(如上面ID = 123),取得它的ROWID,我们知道,ROWID中10~15位表示这条记录所在的BLOCK是数据文件的第几个BLOCK。

A表示0,B为1,G表示6。这说明这条记录在数据文件的第六个block中。

SQL> SHOW PARAMETER DB_BLOCK_SIZE

NAME TYPE VALUE
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
db_block_size integer 16384

BLOCK的大小是16k。

SQL> SELECT TO_CHAR(6*16384, 'XXXXXX') FROM DUAL;

TO_CHAR
- - - - - - -
18000

SQL> SELECT TO_CHAR(7*16384, 'XXXXXX') FROM DUAL;

TO_CHAR
- - - - - - -
1C000

用UtralEdit打开数据文件,将文件定位18000h处(以二进制方式打开,如果没有用二进制打开,可以使用CTRL+H快捷键切换)。根据上面的计算,可以得出,我们要找到记录在18000h和1C000h之间。

Number类型123在数据库存放方式为03C20218,03表示占有三位,C2表示最高位是百位,02表示最高位上是1,18表示低位上是23。

具体的数值可以通过下面的查询得到:

SQL> SELECT DUMP(123) FROM DUAL;

DUMP(123)
- - - - - - - - - - - - - - - - - - - - -
Typ=2 Len=3: 194,2,24

SQL> SELECT TO_CHAR(194, 'XX'), TO_CHAR(2, 'XX'), TO_CHAR(24, 'XX') FROM DUAL;

TO_ TO_ TO_
- - - - - - - - -
C2 2 18

关于具体的NUMBER类型在数据库中是如何存储的,有兴趣的可以参阅另一篇文章。

下面使用UtralEdit的搜索功能,查找到03C20218,将其修改为03C20216,并保存。

上面是通过oracle的ROWID在文件中定位,这相对来说要复杂一些。下面可以使用UtralEdit的功能达到相同的目的。

根据上面的查询可以得到,ID = 123时,NAME的值是ALL_REPCONFLICT。

下面用UtralEdit打开文件,使用CTRL+H方式切换到文本格式,直接查找ALL_REPCONFLICT字符串。找到后,CTRL+H切换回二进制格式。向前跳过一个长度字节(本例中为0F),就可以看到123的值03C20218,进行修改后,保存并退出。

SQL> SELECT * FROM TEST WHERE ID = 123;

ID NAME
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
123 ALL_REPCONFLICT

这时候查询仍然可以得到正确结果,因为oracle使用了db_cache中的结果。为了让oracle“看”到修改,必须重起数据库。

SQL> CONN /@TEST AS SYSDBA
已连接。
SQL> SHUTDOWN
数据库已经关闭。
已经卸载数据库。
ORACLE 例程已经关闭。
SQL> STARTUP
ORACLE 例程已经启动。

Total System Global Area 89201304 bytes
Fixed Size 453272 bytes
Variable Size 62914560 bytes
Database Buffers 25165824 bytes
Redo Buffers 667648 bytes
数据库装载完毕。
数据库已经打开。
SQL> CONN YANGTK/YANGTK@TEST
已连接。

SQL> SELECT * FROM TEST WHERE ID = 123;
SELECT * FROM TEST WHERE ID = 123
*
ERROR 位于第 1 行:
ORA-01578: ORACLE 数据块损坏(文件号7,块号6)
ORA-01110: 数据文件 7: 'E:ORACLEORADATATESTTEST.DBF'

已经模拟成功了坏块,开始进入正题部分,使用DBMS_REPAIR表来处理坏块。

三、使用DBMS_REPAIR包处理坏块。

1.建立REPAIR_TABLE和ORPHAN_KEY_TABLE表

SQL> BEGIN
2 DBMS_REPAIR.ADMIN_TABLES (
3 TABLE_NAME => 'REPAIR_TABLE',
4 TABLE_TYPE => dbms_repair.repair_table,
5 ACTION => dbms_repair.create_action,
6 TABLESPACE => 'YANGTK');
7 END;
8 /

PL/SQL 过程已成功完成。

SQL> BEGIN
2 DBMS_REPAIR.ADMIN_TABLES (
3 TABLE_NAME => 'ORPHAN_KEY_TABLE',
4 TABLE_TYPE => dbms_repair.orphan_table,
5 ACTION => dbms_repair.create_action,
6 TABLESPACE => 'YANGTK');
7 END;
8 /

PL/SQL 过程已成功完成。

REPAIR_TABLE用来记录错误检查结果,ORPHAN_KEY_TABLE用来记录表坏块中记录在索引中对应键值。

这两个表的删除可以通过下列存储过程完成

BEGIN
DBMS_REPAIR.ADMIN_TABLES (
TABLE_NAME => 'REPAIR_TABLE',
TABLE_TYPE => dbms_repair.repair_table,
ACTION => dbms_repair.drop_action);
END;
/

BEGIN
DBMS_REPAIR.ADMIN_TABLES (
TABLE_NAME => 'ORPHAN_KEY_TABLE',
TABLE_TYPE => dbms_repair.orphan_table,
ACTION => dbms_repair.drop_action);
END;
/

2.使用CHECK_OBJECT过程检测坏块。

SQL> SET SERVEROUTPUT ON
SQL> DECLARE
2 num_corrupt INT;
3 BEGIN
4 num_corrupt := 0;
5 DBMS_REPAIR.CHECK_OBJECT (
6 SCHEMA_NAME => 'YANGTK',
7 OBJECT_NAME => 'TEST',
8 REPAIR_TABLE_NAME => 'REPAIR_TABLE',
9 CORRUPT_COUNT => num_corrupt);
10 DBMS_OUTPUT.PUT_LINE('number corrupt: ' || TO_CHAR (num_corrupt));
11 END;
12 /
number corrupt: 1

PL/SQL 过程已成功完成。

SQL> SELECT OBJECT_NAME, BLOCK_ID, CORRUPT_TYPE, MARKED_CORRUPT,
2 CORRUPT_DESCRIPTION, REPAIR_DESCRIPTION
3 FROM REPAIR_TABLE;

OBJECT_NAM BLOCK_ID CORRUPT_TYPE MARKED_COR CORRUPT_DE REPAIR_DESCRIPTION
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TEST 6 6148 TRUE mark block software corrupt

这里和oracle文档上面有点出入,根据oracle文档上面介绍MARKED_CORRUPT列的值是FALSE,只有执行了FIX_CORRUPT_BLOCKS过程才会使MARKED_CORRUPT列的值变为TRUE。怀疑oracle在CHECK的同时,自动进行FIX_CORRUPT_BLOCKS的操作。

SQL> DECLARE
2 num_fix INT;
3 BEGIN
4 num_fix := 0;
5 DBMS_REPAIR.FIX_CORRUPT_BLOCKS (
6 SCHEMA_NAME => 'YANGTK',
7 OBJECT_NAME=> 'TEST',
8 OBJECT_TYPE => dbms_repair.table_object,
9 REPAIR_TABLE_NAME => 'REPAIR_TABLE',
10 FIX_COUNT=> num_fix);
11 DBMS_OUTPUT.PUT_LINE('num fix: ' || TO_CHAR(num_fix));
12 END;
13 /
num fix: 0

PL/SQL 过程已成功完成。

果然,执行FIX_CORRUPT_BLOCKS过程发现FIX了0个坏块,这一步操作可以省略不用执行。

3.使用DUMP_ORPHAN_KEYS过程来保存坏块中的索引键值。

这时还存在着一个潜在的问题。表出现了坏块,但是索引没有损坏,通过表扫描回出现错误,但是通过索引扫描,仍然可以返回结果,这会造成数据的不一致性。

SQL> SELECT * FROM YANGTK.TEST WHERE ID = 123;
SELECT * FROM YANGTK.TEST WHERE ID = 123
*
ERROR 位于第 1 行:
ORA-01578: ORACLE 数据块损坏(文件号7,块号6)
ORA-01110: 数据文件 7: 'E:ORACLEORADATATESTTEST.DBF'

SQL> SELECT ID FROM YANGTK.TEST WHERE ID = 123;

ID
- - - - - - - - - -
123

通过使用DUMP_ORPHAN_KEYS过程来保存坏块中的索引键值,这样当执行完SKIP_CORRUPT_BLOCKS操作后,就可以重新建立索引了。

SQL> DECLARE
2 num_orphans INT;
3 BEGIN
4 num_orphans := 0;
5 DBMS_REPAIR.DUMP_ORPHAN_KEYS (
6 SCHEMA_NAME => 'YANGTK',
7 OBJECT_NAME => 'IND_TEST_ID',
8 OBJECT_TYPE => dbms_repair.index_object,
9 REPAIR_TABLE_NAME => 'REPAIR_TABLE',
10 ORPHAN_TABLE_NAME=> 'ORPHAN_KEY_TABLE',
11 KEY_COUNT => num_orphans);
12 DBMS_OUTPUT.PUT_LINE('orphan key count: ' || TO_CHAR(num_orphans));
13 END;
14 /
orphan key count: 549

PL/SQL 过程已成功完成。

SQL> DECLARE
2 num_orphans INT;
3 BEGIN
4 num_orphans := 0;
5 DBMS_REPAIR.DUMP_ORPHAN_KEYS (
6 SCHEMA_NAME => 'YANGTK',
7 OBJECT_NAME => 'IND_TEST_NAME',
8 OBJECT_TYPE => dbms_repair.index_object,
9 REPAIR_TABLE_NAME => 'REPAIR_TABLE',
10 ORPHAN_TABLE_NAME=> 'ORPHAN_KEY_TABLE',
11 KEY_COUNT => num_orphans);
12 DBMS_OUTPUT.PUT_LINE('orphan key count: ' || TO_CHAR(num_orphans));
13 END;
14 /
orphan key count: 549

PL/SQL 过程已成功完成。

注意对每个索引都要执行DUMP_ORPHAN_KEYS过程。

4.使用REBUILD_FREELISTS过程来修改FREELISTS。

如果坏块发生在FREELIST列表中的中部,则FREELIST列表后面的块都无法访问,在这个例子中,由于是人为产生的错误,清楚错误的位置不在FREELIST中,因此可以跳过此步骤,一般情况下,无法定位坏块位置,则需要执行改过程。

SQL> BEGIN
2 DBMS_REPAIR.REBUILD_FREELISTS (
3 SCHEMA_NAME => 'YANGTK',
4 OBJECT_NAME => 'TEST',
5 OBJECT_TYPE => dbms_repair.table_object);
6 END;
7 /

PL/SQL 过程已成功完成。

5.执行SKIP_CORRUPT_BLOCKS过程,是后续DML操作跳过坏块

SQL> BEGIN
2 DBMS_REPAIR.SKIP_CORRUPT_BLOCKS (
3 SCHEMA_NAME => 'YANGTK',
4 OBJECT_NAME => 'TEST',
5 OBJECT_TYPE => dbms_repair.table_object,
6 FLAGS => dbms_repair.skip_flag);
7 END;
8 /

PL/SQL 过程已成功完成。

SQL> SELECT OWNER, TABLE_NAME, SKIP_CORRUPT FROM DBA_TABLES
2 WHERE OWNER = 'YANGTK';

OWNER TABLE_NAME SKIP_COR
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
YANGTK TEST ENABLED
YANGTK TEST1 DISABLED
YANGTK TEST_AAA DISABLED
YANGTK TEST_PART DISABLED

已选择4行。

6.重建索引

由于数据和索引仍然存在不一致的问题,因此必须重建索引。

SQL> SELECT * FROM YANGTK.TEST WHERE ID = 123;

未选定行

SQL> SELECT ID FROM YANGTK.TEST WHERE ID = 123;

ID
- - - - - - - - - -
123

SQL> ALTER INDEX YANGTK.IND_TEST_ID REBUILD;

索引已更改。

SQL> SELECT ID FROM YANGTK.TEST WHERE ID = 123;

ID
- - - - - - - - - -
123

注意一点,重建索引一点要先DROP,然后再CREATE,使用REBUILD的方式,重建的数据源来自索引,仍然会导致问题的产生。

SQL> DROP INDEX YANGTK.IND_TEST_ID;

索引已丢弃。

SQL> DROP INDEX YANGTK.IND_TEST_NAME;

索引已丢弃。

SQL> CREATE INDEX YANGTK.IND_TEST_ID ON YANGTK.TEST(ID);

索引已创建。

SQL> CREATE INDEX YANGTK.IND_TEST_NAME ON YANGTK.TEST(NAME);

索引已创建。

SQL> SELECT ID FROM YANGTK.TEST WHERE ID = 123;

未选定行

SQL> SELECT MIN(ID) FROM YANGTK.TEST;

MIN(ID)

- - - - - - - - - -

550

包含ID = 123的块已经别标识为坏块。现在可以看到,最小的ID是550,也就是说,这个坏块中包含了549条记录。

SQL> SELECT COUNT(*) FROM ORPHAN_KEY_TABLE;

COUNT(*)

- - - - - - - - - -

1098

继续查询ORPHAN_KEY_TABLE表,可以发现,这些记录的索引(2个)已经被保存到了ORPHAN_KEY_TABLE表中。

四、恢复数据

使用DBMS_REPAIR包的目的不仅是为了使表重新可以访问,而且,使用这个包还能在一定程度上恢复被因坏块而无法读取的数据。

由于坏块产生在表上,因此索引是可以访问,所有被索引的列的数据都可以恢复。遗憾的是,Oracle的文档并没有给出恢复的方法,我查询了METALINK和ASKTOM也没有找到相应的答案,所以,恢复的工作只能靠自己摸索进行。因此,我并不能保证我的方法一定是正确的,如果想将这种方法应用的正式环境中,请慎重考虑,本人不承担任何责任。:)

言归正传,在上面的步骤中,使用DUMP_ORPHAN_KEYS过程保存了坏块中的索引键值,下面就通过这些保存的键值来进行数据的恢复。

先看一下ORPHAN_KEY_TABLE的表结构:

SQL> DESC ORPHAN_KEY_TABLE
名称 是否为空? 类型
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SCHEMA_NAME NOT NULL VARCHAR2(30)
INDEX_NAME NOT NULL VARCHAR2(30)
IPART_NAME VARCHAR2(30)
INDEX_ID NOT NULL NUMBER
TABLE_NAME NOT NULL VARCHAR2(30)
PART_NAME VARCHAR2(30)
TABLE_ID NOT NULL NUMBER
KEYROWID NOT NULL ROWID
KEY NOT NULL ROWID
DUMP_TIMESTAMP NOT NULL DATE

由于字段名基本上都是自解释的,这里就不在过多描述了,需要说明的是KEYROWID和KEY两个字段。

KEYROWID存放的是该索引键值对应的表中的rowid,而KEY保存的就是索引的键值。

但是查询KEY的值发现,并非像想象中一样,存放的是1、2、3……或ALL_TABLES、ACCESS$……等值,而是以ROWID方式存放的。

SQL> SELECT KEY FROM ORPHAN_KEY_TABLE WHERE INDEX_NAME = 'IND_TEST_ID' AND ROWNUM = 1;

KEY
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*BAAAAAACwQL+

SQL> SELECT KEY FROM ORPHAN_KEY_TABLE WHERE INDEX_NAME = 'IND_TEST_NAME' AND ROWNUM = 1;

KEY
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*BAAAAAAHQUNDRVNTJP4

这种ROWID格式如何转化为NUMBER或VARCHAR2类型呢?查询文档并没有找到相应的解决方法。

于是抱着尝试的想法,觉得DUMP一下,看看数据的结构是怎样的。

SQL> SELECT DUMP(KEY) FROM ORPHAN_KEY_TABLE WHERE INDEX_NAME = 'IND_TEST_ID' AND ROWNUM < 6;

DUMP(KEY)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Typ=208 Len=10: 2,4,0,0,0,0,2,193,2,254
Typ=208 Len=10: 2,4,0,0,0,0,2,193,3,254
Typ=208 Len=10: 2,4,0,0,0,0,2,193,4,254
Typ=208 Len=10: 2,4,0,0,0,0,2,193,5,254
Typ=208 Len=10: 2,4,0,0,0,0,2,193,6,254

这回看到希望了。还记得上面修改数据文件时123的编码吗?是不是和第一个查询中的结果很相似?

2,4,0,0,0,0前几位是不变的,最后一位254也是不变的。中间的部分就是有意义的数字了。其中第一个2表示长度是2,193表示最高位是个位,2表示最高位上的值是1,也就是说,第一个键值是数字1。

SQL> SELECT DUMP(1) FROM DUAL;

DUMP(1)
- - - - - - - - - - - - - - - - - -
Typ=2 Len=2: 193,2

Oracle把数据在文件中的存储格式保存在ROWID字段中了。根据这个假设,我们看看字符串是不是以同样方式存储的。

SQL> SELECT DUMP(KEY) FROM ORPHAN_KEY_TABLE WHERE INDEX_NAME = 'IND_TEST_NAME' AND ROWNUM < 6;

DUMP(KEY)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Typ=208 Len=15: 2,4,0,0,0,0,7,65,67,67,69,83,83,36,254
Typ=208 Len=17: 2,4,0,0,0,0,9,65,71,71,88,77,76,73,77,80,254
Typ=208 Len=23: 2,4,0,0,0,0,15,65,71,71,88,77,76,73,78,80,85,84,84,89,80,69,254
Typ=208 Len=22: 2,4,0,0,0,0,14,65,76,76,95,65,76,76,95,84,65,66,76,69,83,254
Typ=208 Len=17: 2,4,0,0,0,0,9,65,76,76,95,65,80,80,76,89,254

显然7代表长度,后面跟着的明显就是ASCII编码。

SQL> SELECT CHR(65)||CHR(67)||CHR(67)||CHR(69)||CHR(83)||CHR(83)||CHR(36) FROM DUAL;

CHR(65)
- - - - - - -
ACCESS$

知道这个规律,就可以着手进行恢复了,首先先了一个小程序用来把ROWID类型转换为NUMBER类型或VARCHAR2类型。

SQL> CREATE OR REPLACE FUNCTION F_DUMP_FROM_ROWID
2 (
3 P_TYPE IN VARCHAR2,
4 P_DUMP_ROWID IN UROWID
5 )
6 RETURN VARCHAR2 AS
7 V_DUMP_ROWID VARCHAR2(1000);
8 V_NUMBER_STR VARCHAR2(1000);
9 V_POSITION NUMBER;
10 V_NUMBER VARCHAR2(2);
11 BEGIN
12 SELECT DUMP(P_DUMP_ROWID, 16, 7) INTO V_DUMP_ROWID FROM DUAL;
13 V_DUMP_ROWID := SUBSTR(V_DUMP_ROWID, INSTR(V_DUMP_ROWID, ',') + 1);
14 V_DUMP_ROWID := SUBSTR(V_DUMP_ROWID, 1, LENGTH(V_DUMP_ROWID) - 3);
15
16 IF P_TYPE = 'VARCHAR2' THEN
17 V_DUMP_ROWID := REPLACE(V_DUMP_ROWID , ',');
18 RETURN(UTL_RAW.CAST_TO_VARCHAR2(V_DUMP_ROWID));
19 ELSIF P_TYPE = 'NUMBER' THEN
20 V_DUMP_ROWID := V_DUMP_ROWID || ',';
21 V_POSITION := INSTR(V_DUMP_ROWID, ',');
22
23 WHILE (V_POSITION != 0) LOOP
24 V_NUMBER := SUBSTR(V_DUMP_ROWID, 1, V_POSITION - 1);
25 V_DUMP_ROWID := SUBSTR(V_DUMP_ROWID, V_POSITION + 1);
26
27 IF V_POSITION = 2 THEN
28 V_NUMBER_STR := V_NUMBER_STR || '0' || V_NUMBER;
29 ELSIF V_POSITION = 3 THEN
30 V_NUMBER_STR := V_NUMBER_STR || V_NUMBER;
31 ELSE
32 RAISE_APPLICATION_ERROR(-20002, 'DUMP ERROR CHECK THE INPUT ROWID');
33 END IF;
34
35 V_POSITION := INSTR(V_DUMP_ROWID, ',');
36 END LOOP;
37
38 V_NUMBER_STR := REPLACE(V_NUMBER_STR , ',');
39
40 RETURN(UTL_RAW.CAST_TO_NUMBER(V_NUMBER_STR));
41 ELSE
42 RAISE_APPLICATION_ERROR(-20001, 'TYPE NOT VALID OR CAN''T TRANSALTE ' || P_TYPE || ' TYPE');
43 END IF;
44 END;
45 /

函数已创建。

测试一下函数的功能。

SQL> SELECT F_DUMP_FROM_ROWID('NUMBER', KEY) FROM ORPHAN_KEY_TABLE
2 WHERE INDEX_NAME = 'IND_TEST_ID' AND ROWNUM < 6;

F_DUMP_FROM_ROWID('NUMBER',KEY)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1
2
3
4
5

SQL> SELECT F_DUMP_FROM_ROWID('VARCHAR2', KEY) FROM ORPHAN_KEY_TABLE
2 WHERE INDEX_NAME = 'IND_TEST_NAME' AND ROWNUM < 6;

F_DUMP_FROM_ROWID('VARCHAR2',KEY)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ACCESS$
AGGXMLIMP
AGGXMLINPUTTYPE
ALL_ALL_TABLES
ALL_APPLY

好了,剩下的事情就简单了。我们将ORPHAN_KEY_TABLE表中的记录转变后,重新插入到TEST表中即可。

SQL> INSERT INTO YANGTK.TEST (ID, NAME)
2 SELECT
3 F_DUMP_FROM_ROWID('NUMBER', A.KEY),
4 F_DUMP_FROM_ROWID('VARCHAR2', B.KEY)
5 FROM ORPHAN_KEY_TABLE A, ORPHAN_KEY_TABLE B
6 WHERE A.KEYROWID = B.KEYROWID
7 AND A.INDEX_NAME = 'IND_TEST_ID'
8 AND B.INDEX_NAME = 'IND_TEST_NAME';

已创建549行。

SQL> SELECT * FROM YANGTK.TEST WHERE ID = 1;

ID NAME
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1 ACCESS$

SQL> SELECT * FROM YANGTK.TEST WHERE ID = 123;

ID NAME
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
123 ALL_REPCONFLICT

SQL> COMMIT;

至此,数据恢复已经完成。

最后,需要说明几点。

我只做了NUMBER类型和VARCHAR2类型的恢复测试,其他类型的恢复还没有测试,目前我做的函数也只包含了恢复NUMBER和VARCHAR2类型的功能。而且,目前只进行了单列B数索引的恢复,组合索引、BITMAP索引等其它类型索引没有测试。另外,如果VARCHAR2(CHAR)类型中包含中文,在ZHS16GBK字符集下我测试通过,其他字符集没有测试,但估计对于一般中文字符集都不会有问题,但是单字节字符集可能会有问题。

2、使用Rman进行恢复:

首先要存在Rman的最新备份集,然后执行如下命令:
RMAN>backup validate datafile 4;检查4号数据文件是否存在坏块
执行查询:select * from v$database_block_corruption where file#=4;
如果4号文件存在坏块的话,那么将在结果集中有所显示,会显示损坏的块号,根据显示结果执行如下命令进行恢复:
RMAN>blockrecover datafile 4 block 35 from backupset;
该命令执行后即可恢复坏块,并且不会造成数据丢失,但是要求数据库必须要运行在归档模式下,否则RMAN无法发挥作用,而且通过RMAN做过最新的数据库备份

3、使用bbed恢复

使用bbed恢复时必须有数据文件的拷贝。
bbed就是英文block browse edit的缩写,用来直接查看和修改数据文件数据的一个工具。
在windows和linux上面都有
但在linux下需要编译:
然后把$ORACLE_HOME/rdbms/lib加到环境变量的PATH里面,就可以直接在命令中bbed了。
BBED的缺省口令为blockedit,For Oracle Internal Use only 请谨慎使用Oracle不做技术支持。
[oracle@test oracle]$ cd $ORACLE_HOME/rdbms/lib
[oracle@test lib]$ make -f ins_rdbms.mk $ORACLE_HOME/rdbms/lib/bbed
进入bbed后,可以使用help查看帮助
BBED> help

bbed的详细用法在eygle的文章里有介绍

http://www.eygle.com/archives/2012/06/dbv_corrupt_block_relative_dba.html

DBV 坏块检测:Corrupt block relative dba之源

作者:eygle |English 【转载时请标明出处和作者信息】
链接:http://www.eygle.com/archives/2012/06/dbv_corrupt_block_relative_dba.html
站内相关文章|Related Articles
Oracle数据恢复:文件 数据错误(循环冗余检查) 解决
Oracle数据恢复:数据文件头的SCN与时间校验
How to repair corruption block use BBED?
How to simulate block corruption with BBED?
在使用dbv进行坏块检测时,会抛出文件号、块号等信息,这个信息来自于文件头的信息记录。

以下是验证说明,正常情况下的检测输出:
[orat0@hpserver2 lib]$ dbv file=/app/oracle/product/10.2.0/dbf.ggx blocksize=8192 start=1 end=3

DBVERIFY: Release 10.2.0.5.0 - Production on Tue Jun 5 16:04:10 2012

Copyright (c) 1982, 2007, Oracle. All rights reserved.

DBVERIFY - Verification starting : FILE = dbf.ggx

DBVERIFY - Verification complete

Total Pages Examined : 3
Total Pages Processed (Data) : 0
Total Pages Failing (Data) : 0
Total Pages Processed (Index): 0
Total Pages Failing (Index): 0
Total Pages Processed (Other): 3
Total Pages Processed (Seg) : 0
Total Pages Failing (Seg) : 0
Total Pages Empty : 0
Total Pages Marked Corrupt : 0
Total Pages Influx : 0
Highest block SCN : 796355 (0.796355)

通过BBED进行修改,
[orat0@hpserver2 lib]$ bbed parfile=par.txt

BBED: Release 2.0.0.0.0 - Limited Production on Tue Jun 5 16:04:16 2012

Copyright (c) 1982, 2007, Oracle. All rights reserved.

* !!! For Oracle Internal Use only !!! ***

BBED> set file 3
BBED-00205: illegal or out of range DBA (File 3, Block 1)

BBED> p u^U
BBED> set file 2
FILE# 2

BBED> p kcvfh
struct kcvfh, 676 bytes @0
struct kcvfhbfh, 20 bytes @0
ub1 type_kcbh @0 0x0b
ub1 frmt_kcbh @1 0xa2
ub1 spare1_kcbh @2 0x00
ub1 spare2_kcbh @3 0x00
ub4 rdba_kcbh @4 0x01400001
ub4 bas_kcbh @8 0x00000000
ub2 wrp_kcbh @12 0x0000
ub1 seq_kcbh @14 0x01
ub1 flg_kcbh @15 0x04 (KCBHFCKV)
ub2 chkval_kcbh @16 0xe0b1
ub2 spare3_kcbh @18 0x0000
struct kcvfhhdr, 76 bytes @20
ub4 kccfhswv @20 0x00000000
ub4 kccfhcvn @24 0x0a200000
ub4 kccfhdbi @28 0x392986ff
text kccfhdbn[0] @32 O
text kccfhdbn[1] @33 R
text kccfhdbn[2] @34 C
text kccfhdbn[3] @35 L
text kccfhdbn[4] @36 1
text kccfhdbn[5] @37 0
text kccfhdbn[6] @38 G
text kccfhdbn[7] @39
ub4 kccfhcsq @40 0x0000156a
ub4 kccfhfsz @44 0x00000280
s_blkz kccfhbsz @48 0x00
ub2 kccfhfno @52 0x0005
ub2 kccfhtyp @54 0x0003
ub4 kccfhacid @56 0x00000000
ub4 kccfhcks @60 0x00000000
text kccfhtag[0] @64
text kccfhtag[1] @65
text kccfhtag[2] @66
text kccfhtag[3] @67
text kccfhtag[4] @68
text kccfhtag[5] @69
text kccfhtag[6] @70
text kccfhtag[7] @71
text kccfhtag[8] @72
text kccfhtag[9] @73
text kccfhtag[10] @74
text kccfhtag[11] @75
text kccfhtag[12] @76
text kccfhtag[13] @77
text kccfhtag[14] @78
text kccfhtag[15] @79
text kccfhtag[16] @80
text kccfhtag[17] @81
text kccfhtag[18] @82
text kccfhtag[19] @83
text kccfhtag[20] @84
text kccfhtag[21] @85
text kccfhtag[22] @86
text kccfhtag[23] @87
text kccfhtag[24] @88
text kccfhtag[25] @89
text kccfhtag[26] @90
text kccfhtag[27] @91
text kccfhtag[28] @92
text kccfhtag[29] @93
text kccfhtag[30] @94
text kccfhtag[31] @95
ub4 kcvfhrdb @96 0x00000000
struct kcvfhcrs, 8 bytes @100
ub4 kscnbas @100 0x0009582c
ub2 kscnwrp @104 0x0000
ub4 kcvfhcrt @108 0x2e2e3876
ub4 kcvfhrlc @112 0x2e2c08bf
struct kcvfhrls, 8 bytes @116
ub4 kscnbas @116 0x00000001
ub2 kscnwrp @120 0x0000
ub4 kcvfhbti @124 0x00000000
struct kcvfhbsc, 8 bytes @128
ub4 kscnbas @128 0x00000000
ub2 kscnwrp @132 0x0000
ub2 kcvfhbth @136 0x0000
ub2 kcvfhsta @138 0x0004 (KCVFHOFZ)
struct kcvfhckp, 36 bytes @484
struct kcvcpscn, 8 bytes @484
ub4 kscnbas @484 0xf00ed6dd
ub2 kscnwrp @488 0x0bab
ub4 kcvcptim @492 0x2ec9f476
ub2 kcvcpthr @496 0x0001
union u, 12 bytes @500
struct kcvcprba, 12 bytes @500
ub4 kcrbaseq @500 0x00000080
ub4 kcrbabno @504 0x00000002
ub2 kcrbabof @508 0x0010
ub1 kcvcpetb[0] @512 0x02
ub1 kcvcpetb[1] @513 0x00
ub1 kcvcpetb[2] @514 0x00
ub1 kcvcpetb[3] @515 0x00
ub1 kcvcpetb[4] @516 0x00
ub1 kcvcpetb[5] @517 0x00
ub1 kcvcpetb[6] @518 0x00
ub1 kcvcpetb[7] @519 0x00
ub4 kcvfhcpc @140 0x000000d5
ub4 kcvfhrts @144 0x2ec00569
ub4 kcvfhccc @148 0x000000d4
struct kcvfhbcp, 36 bytes @152
struct kcvcpscn, 8 bytes @152
ub4 kscnbas @152 0x00000000
ub2 kscnwrp @156 0x0000
ub4 kcvcptim @160 0x00000000
ub2 kcvcpthr @164 0x0000
union u, 12 bytes @168
struct kcvcprba, 12 bytes @168
ub4 kcrbaseq @168 0x00000000
ub4 kcrbabno @172 0x00000000
ub2 kcrbabof @176 0x0000
ub1 kcvcpetb[0] @180 0x00
ub1 kcvcpetb[1] @181 0x00
ub1 kcvcpetb[2] @182 0x00
ub1 kcvcpetb[3] @183 0x00
ub1 kcvcpetb[4] @184 0x00
ub1 kcvcpetb[5] @185 0x00
ub1 kcvcpetb[6] @186 0x00
ub1 kcvcpetb[7] @187 0x00
ub4 kcvfhbhz @312 0x00000000
struct kcvfhxcd, 16 bytes @316
ub4 space_kcvmxcd[0] @316 0x00000000
ub4 space_kcvmxcd[1] @320 0x00000000
ub4 space_kcvmxcd[2] @324 0x00000000
ub4 space_kcvmxcd[3] @328 0x00000000
word kcvfhtsn @332 5
ub2 kcvfhtln @336 0x0003
text kcvfhtnm[0] @338 G
text kcvfhtnm[1] @339 G
text kcvfhtnm[2] @340 X
text kcvfhtnm[3] @341
text kcvfhtnm[4] @342
text kcvfhtnm[5] @343
text kcvfhtnm[6] @344
text kcvfhtnm[7] @345
text kcvfhtnm[8] @346
text kcvfhtnm[9] @347
text kcvfhtnm[10] @348
text kcvfhtnm[11] @349
text kcvfhtnm[12] @350
text kcvfhtnm[13] @351
text kcvfhtnm[14] @352
text kcvfhtnm[15] @353
text kcvfhtnm[16] @354
text kcvfhtnm[17] @355
text kcvfhtnm[18] @356
text kcvfhtnm[19] @357
text kcvfhtnm[20] @358
text kcvfhtnm[21] @359
text kcvfhtnm[22] @360
text kcvfhtnm[23] @361
text kcvfhtnm[24] @362
text kcvfhtnm[25] @363
text kcvfhtnm[26] @364
text kcvfhtnm[27] @365
text kcvfhtnm[28] @366
text kcvfhtnm[29] @367
ub4 kcvfhrfn @368 0x00000005
struct kcvfhrfs, 8 bytes @372
ub4 kscnbas @372 0x00000000
ub2 kscnwrp @376 0x0000
ub4 kcvfhrft @380 0x2e2e4052
struct kcvfhafs, 8 bytes @384
ub4 kscnbas @384 0x00000000
ub2 kscnwrp @388 0x0000
ub4 kcvfhbbc @392 0x00000000
ub4 kcvfhncb @396 0x00000000
ub4 kcvfhmcb @400 0x00000000
ub4 kcvfhlcb @404 0x00000000
ub4 kcvfhbcs @408 0x00000000
ub2 kcvfhofb @412 0x0000
ub2 kcvfhnfb @414 0x0000
ub4 kcvfhprc @416 0x00000000
struct kcvfhprs, 8 bytes @420
ub4 kscnbas @420 0x00000000
ub2 kscnwrp @424 0x0000
struct kcvfhprfs, 8 bytes @428
ub4 kscnbas @428 0x00000000
ub2 kscnwrp @432 0x0000
ub4 kcvfhtrt @444 0x00000000

偏移量 368 处为: kcvfhrfn ,这就是文件号的来源,具有决定性影响。

BBED> set offset 368
OFFSET 368

BBED> dump
File: /t0/orat0/app/oracle/product/10.2.0/db_1/rdbms/lib/dbf.ggx (2)
Block: 1 Offsets: 368 to 879 Dba:0x00800001
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
05000000 00000000 00000000 52402e2e 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 ddd60ef0 ab0b2e7c 76f4c92e
01008e00 80000000 02000000 10000000 02000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 0d000d00 0d000100 00000000
00000000 00000000 02004001 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

<32 bytes per line>

将文件号修改为 07 :
BBED> modify /x 07
Warning: contents of previous BIFILE will be lost. Proceed? (Y/N) Y
File: /t0/orat0/app/oracle/product/10.2.0/db_1/rdbms/lib/dbf.ggx (2)
Block: 1 Offsets: 368 to 879 Dba:0x00800001
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
07000000 00000000 00000000 52402e2e 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 ddd60ef0 ab0b2e7c 76f4c92e
01008e00 80000000 02000000 10000000 02000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 0d000d00 0d000100 00000000
00000000 00000000 02004001 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

<32 bytes per line>

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

BBED> exit

再检测时可以发现文件号变更为 7 ,所有块都被标记为坏块:

[orat0@hpserver2 lib]$ dbv file=dbf.ggx blocksize=8192 start=1 end=3

DBVERIFY: Release 10.2.0.5.0 - Production on Tue Jun 5 16:06:35 2012

Copyright (c) 1982, 2007, Oracle. All rights reserved.

DBVERIFY - Verification starting : FILE = dbf.ggx
Page 1 is marked corrupt
Corrupt block relative dba: 0x01c00001 (file 7, block 1)
Bad header found during dbv:
Data in bad block:
type: 11 format: 2 rdba: 0x01400001
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: 0xe0b3
computed block checksum: 0x0

Page 2 is marked corrupt
Corrupt block relative dba: 0x01c00002 (file 7, block 2)
Bad header found during dbv:
Data in bad block:
type: 29 format: 2 rdba: 0x01400002
last change scn: 0x0000.000c26c3 seq: 0x2 flg: 0x04
spare1: 0x0 spare2: 0x0 spare3: 0x0
consistency value in tail: 0x26c31d02
check value in block header: 0xbb3c
computed block checksum: 0x0

Page 3 is marked corrupt
Corrupt block relative dba: 0x01c00003 (file 7, block 3)
Bad header found during dbv:
Data in bad block:
type: 30 format: 2 rdba: 0x01400003
last change scn: 0x0000.000c26c3 seq: 0x1 flg: 0x04
spare1: 0x0 spare2: 0x0 spare3: 0x0
consistency value in tail: 0x26c31e01
check value in block header: 0x4ebc
computed block checksum: 0x0

DBVERIFY - Verification complete

Total Pages Examined : 3
Total Pages Processed (Data) : 0
Total Pages Failing (Data) : 0
Total Pages Processed (Index): 0
Total Pages Failing (Index): 0
Total Pages Processed (Other): 0
Total Pages Processed (Seg) : 0
Total Pages Failing (Seg) : 0
Total Pages Empty : 0
Total Pages Marked Corrupt : 3
Total Pages Influx : 0
Highest block SCN : 0 (0.0)
文件头有3处信息与文件号有关,但是仅此处与DBV检测相关。

测试环境为10g,10.2.0.5版本。


本页面的文字允许在知识共享 署名-相同方式共享 3.0协议和GNU自由文档许可证下修改和再使用,仅有一个特殊要求,请用链接方式注明文章引用出处及作者。请协助维护作者合法权益。


系列文章

文章列表

  • Oracle Block Corruption的检测与处理

这篇文章对你有帮助吗,投个票吧?

rating: 0+x

留下你的评论

Add a New Comment