1.1 物理坏块和逻辑坏块

Oracle数据文件的坏块可以分为物理坏块和逻辑坏块。物理坏块指的是块格式本身已经损坏,块内的数据没有任何意义。而逻辑坏块,指的是块内的数据在逻辑上存在问题,比如说索引块的索引值没有按从小到大排列导致的逻辑坏块。物理坏块一般是由于内存问题、OS问题、I/O子系统问题或硬件引起的,逻辑坏块一般是有Oracle bug等原因引起的。

各种各样的块损坏通常是通过OracleORA-1578错误报告出来的,详细的损坏描述会在告警日志中打印出来。

1.1.2 物理块损坏

块的物理损坏有很多种情况,例如块头(Cache Header)被一个不正确的值替换、块被破坏或变得不完整、块的头和尾不匹配、块的校验和(CHECKSUM)不正确、块错位、块被归零。

1)破裂块

一个破裂块的意思即块是不完整的,块头的信息不能匹配块尾的信息。在告警日志中可能出现如下的日志信息:

Corrupt block relative dba:0x0380e573(file 14,block 58739)

Fractured block found during buffer read

……

2)不正确的校验和

块的校验和也是数据块的一致性检查的依据。块的一致性检查由DB_BLOCK_CHECKSUMDB_BLOCK_CHECKING两个初始化参数控制。DB_BLOCK_CHECKSUM是一种物理检查,DB_CHECK_CHECKING是一种逻辑检查。

参数1 DB_CHECK_CHECKSUM

DB_BLOCK_CHECKSUM只有在写入(DBWn常规写或用户进程直接路径写入)时,根据一个CHECKSUM算法计算数据块的校验和,然后写入数据块的一个特定位置(CACHE HEADER,具体是以0字节算起,块的第16~17字节),在读取块时再进行检验。主要是防止I/O硬件和I/O子系统的错误。

CHECKSUM的算法只是根据块的字节值计算一个校验和,算法比较简单。该参数默认在所有表空间上都起作用。

DB_BLOCK_CHECKSUM参数属性

属性

描述

语法

DB_BLOCK_CHECKSUM={OFF|FALSE|TYPICAL|TURE|FULL}

默认值

TYPICAL

修改范围

ALTER SESSION,ALTER SYSTEM

只有当参数值是TYPICAL或者FULL,并且块的最后一次写是存储了一个校验和时,读取这个块,校验和才会被验证。在FULL模式,Oracleupdate/delete语句改变数据之前会验证校验和,改变被应用之后还会重新计算校验和。

Oracle Database 11g开始,大多数日志校验和都是通过前台进程产生的,同时LGWR执行其余的工作,这是为了更好地发挥CPU和缓存的效率。当这个参数设置为FULL,写日志块到磁盘之前,LGWR验证通过前台进程生成的每个日志块的校验和。在Oracle Database 11g之前的版本中,LGWR独自执行日志块校验和。数据文件块的校验和是由DBWR进程负责计算和管理的。

这个参数设置为OFF时,DBWn只为SYSTEM表空间计算校验和,不为用户表空间计算校验和。另外,此时数据库也不会执行日志的校验工作。

校验和可以使Oracle数据库察觉到磁盘、存储系统或者I/O系统引起的损坏。如果设置为FULL,DB_BLOCK_CHECKSUM也会捕捉在内存中的损坏,并停止它们对磁盘的操作。设置这个参数为TYPICAL值只会引起系统额外的1%~2%的负载,设置为FULL会引起4%~5%的负载。Oracle推荐设置DB_BLOCK_CHECKSUMTYPICAL。为了保持向后兼容性,TRUEFALSE值被保留,TRUE等同于TYPICALFALSE等同于OFF

如果DB_BLOCK_CHECKSUM不等于FALSE值,每次读取块,Oracle计算校验和,都与存储在块头中的校验和进行对比。如下例子:

Corrupt block relative dba: 0x0380a58f (file 14,block 42383)

Bad check value found during buffer read

……

参数2 DB_BLOCK_CHECKING

DB_BLOCK_CHECKING参数主要是用于数据块的逻辑一致检查,但只是在块内,不包括块间的逻辑检查。主要用于防止在内存中损坏或数据损坏。

无论该参数如何设置,对SYSTEM表空间来说,逻辑一致检查始终处于打开状态,在其他表空间该参数默认是关闭的。

DB_BLOCK_CHECKING参数的属性

参数值

含义

OFF或者FALSE

对于用户表空间没有任何逻辑一致性检查工作

LOW

块的内容在内存中改变之后,执行基本的块头检查,如UPDATE语句、INSERT语句、磁盘读或者在RAC中内部实例之间的块传递之后发生检查工作

MEDIUM

除了索引以外的所有对象执行LOW检查和完全语义检查,由于索引能在遭遇损坏的情况下的重建,所以可以不考虑对它检查

FULL或者TRUE

所有对象执行MEDIUM检查和完全语义检查

Oracle通过遍历在块中的数据来检查一个块,确保它在逻辑上手尾一致。根据系统负载和参数值,块检查通常一起1%~10%的负载。打开块检查,大量的UPDATE或者INSERT将造成更大负载,对于一个繁忙的系统,特别有大量插入或者更新操作的系统来说,性能影响是比较明显的。如果性能负载可以被接受,应该考虑设置DB_BLOCK_CHECKINGFULL。为了保持向后的兼容性,TUREFALSE参数值同样可以使用,FALSE等同于OFFTRUE等同于FULL

如果启用DB_BLOCK_CHECKING参数,在磁盘的块发生逻辑损坏,下一次块更新将作为软损坏标记这个块,之后读取这个块产生ORA-1578的错误。

3)块错位

Oracle察觉读取块的内容属于不同块但是校验和又是正确的时,会产生错误。

1.1.2 逻辑块损坏

若块包含一个正确的校验和,块头以下的结构是损坏的(块内容损坏),这可能引起不同的ORA-600错误。逻辑块损坏的详细损坏描述通常不会打印到告警日志。DBV将报告块具体的逻辑错误。

1.2 坏块的检测工具

以下为损坏块的检测工具和使用方法:

1.2.1 DBVERIRY坏块验证工具

DBVERIRY不能验证联机Redo日志、归档Redo日志、控制文件和RMAN备份集,只能用于数据文件的块验证。

n  DBV验证传统数据文件

下面是使用DBV工具验证数据文件块的例子:

$ dbv file=/testdb/test01.dbf blocksize=8192

注意:DBV工具除了用于检测数据文件是否有坏块外,也用于获得坏块的详细信息。

n  DBV验证裸设备数据文件

DBV要求file后面跟的必须是一个包含扩展名的文件,所以如果数据库使用裸设备作为存储方式,就必须使用ln命令连接裸设备一个带扩展名的文件,然后使用DBV工具通过对链接文件的验证实现对裸设备数据文件的验证。

n  DBV验证ASM存储的数据文件

如果是验证存储在ASM中的数据文件则需要指定用户名和密码,如果不指定用户名和密码,将收到DBV-00008USERID must bu specified for OSM files的报错。下面是使用DBV工具验证存储在ASM中的数据文件的块的例子:

$ dbv file=+DATAFILE/testdb/datafile/test.234.648839 userid=sys/oracle

1.2.2 ANALYZE命令

Analyze命令的主要目的是通过分析数据库对象,为优化器收集数据库对象的统计量信息,以便优化器生成准确的执行计划。同时,它也能检查某个表或索引是否存在损坏的情况。Analyze执行坏块检查,但是不会标记坏块为corrupt,检测结果保存在USER_DUMP_DEST目录下的用户trace文件中。Analyze语法:

Analyze table/index / validate structure ;

Analyze命令会验证每个数据块、每条记录和索引的完整性。CASCADE关键字表示验证表及其相关的所有索引。与DBVERIFY不同的是,analyze只验证高水位线以下的数据块,analyze不会对未使用的空间进行验证。

SQL> analyze table fengpin.test validate structure;

1.2.3 RMAN工具

RMAN是一块备份工具,就像一个过滤器,RMAN需要通过缓存过滤每一个块,其中一个特点就是检查块是否被损坏。如果备份的数据库中包含有坏块,将会收到错误

1.2.4 EXP工具

对于包含坏块的表执行导出操作,会收到相关的错误信息。对于这种情况,在非归档模式无法通过块恢复修复块的情况下,有如下两种处理方法:

方法1:启用10231事件

通过设置10231诊断事件可以在导出的时候让Oracle忽略表损坏的块,10231Oracle的内部诊断事件,设置在全表扫描时跳过坏块的数据块,只导出包含正确块的数据,之后把表删除,再把导出的表数据导入新表,从而修复该表。

1  启用10231诊断事件

SQL> alter system set events=’10231 trace name context forever,level 10’;

2  禁用10231诊断事件:

SQL> alter system set events=’10231 trace name context forever,level 0’;

方法2:使用DBMS_REPAIR包标记损坏的块。

可以使用DBMS_REPAIR包标记损坏的数据库对象,这样在对损坏的对象执行全表扫描的时候会跳过损坏的块。语法如下:

SQL> exec dbms_repair.skip_corrupt_blocks(‘’,’tablename’);

EXP坏块检查有一定的局限性,不会发现如下类型的坏块:

ü  HWM(高水位线)以上的坏块

ü  索引中存在的坏块

ü  数据字典中存在的坏块

1.2.4 Expdp工具

使用expdp工具不会给出坏块的提示,只会将对象正确的数据导出。

1.3 块的损坏与恢复

块已经不是Oracle的格式,或者其内部是不一致的,那么这个块就被认为已损坏。块介质恢复是当数据文件是联机时,还原和恢复数据块的技术。如果只有一些块被破坏,那么块介质恢复是较好的恢复选择。

BBEDBlock Brower and EDitor)是Oracle的一款内部工具,可以用来直接查看和修改Oracle数据文件块的内容。BBED是一个针对Oracle的二进制编译工具。该工具不受Oracle支持,默认是不生成可执行文件的,在使用钱需要重新编译。

1.3.1 编译BBED

直接在Oracle 11gR2 的环境中编译BBED,将收到以下错误信息:

$ cd $ORACLE_HOME/rdbms/lib

$ make –f ins_rdbms.mk $ORACLE_HOME/rdbms/lib/bbed

……

gcc: /u01/app/oracle/11.2.0/db_1/rdbms/lib/ssbbded.o: No such file or directory

gcc: /u01/app/oracle/11.2.0/db_1/rdbms/lib/sbbdpt.o: No such file or directory

Oracle 11gR2 环境中编译BBED可执行文件所需要的ssbbded.osbbdpt.o对象文件被移除,不过可以从Oracle 10g环境中将这两个文件拷贝到Oracle 11g环境中进行编译。

除了将上面的ssbbded.osbbdpt.o文件拷贝到Oracle 11g环境外,BBED还需要用到$ORACLE_HOME/rdbms/mesg目录下的bbedus.msgbbedus.msb两个信息文件,这几个文件都需要从Oracle 10g中拷贝到Oracle 11g中对应的目录中。下面是将以上4个文件从Oracle 10g中拷贝到Oracle 11g对应目录之后的编译过程:

$ cd $ORACLE_HOME/rdbms/lib

$ make –f ins_rdbms.mk $ORACLE_HOME/rdbms/lib/bbed

$ file bbed

$ size bbed

$ ldd bbed

$ cp bbed $ORACLE_HOME/bin/

$ cd /

$ which bbed

 /u01/app/oracle/product/11.2.0/db_1/bin/bbed

编译成功后登录BBED,登录时需要密码(默认密码是:blockedit

$ bbed

1.3.2 BBED模拟表数据块的损坏

a. 创建测试表

SQL> create table test.testbbed as select * from dba_tables;

b. 创建BBED参数文件

由于BBED无法对ASM进行操作,所以这里将表创建到ACFS文件系统的存储设备上。这里创建两个BBED参数文件,filelist.txt保存要操作的数据文件的ID和路径,bbed.par保存数据文件的块大小、filelist.txt的位置和操作模式:

$ more filelist.txt

6 /testbbed/tbtbs01.dbf

$ more bbed.par

blocksize=8192

listfile=filelist.txt

mode=edit

filelist.txt的内容可通过select file_idfile_name from dba_data_filesSQL查询得到。

c. BBED基本操作

ü   使用指定的参数文件登录BBED

$ bbed parfile=bbed.par

ü  显示BBED配置文件中指定的数据文件信息:

BBED> info

ü  设置要操作的数据文件:

BBED> set file 6

ü  显示要操作的数据文件的详细信息:

BBED> show

d.        模拟坏块

修改文件号为6的第136号块:

BBED> modify 1000 file 6 block 136

如果修改错误,可以执行revert命令回滚。

e.        验证坏块

BBED执行以下命令验证数据块,发现block 136已经损坏

BBED> verify

f.         使用DBV工具验证

使用DBV工具验证发现file 6 block 136已经损坏

$ dbv file=/testbbed/tbtbs01.dbf blocksize=8192

g.        执行块读取操作

执行一个test.testbbed的全表扫描,收到ORA-01578错误

SQL> alter system flush buffer_cache;

SQL> select /*+FULL(T)*/ COUNT(1) FROM TEST.TESTBBED T;

1.3.3 RMAN的块恢复

块介质恢复用来恢复一个单独的块或者数据文件中数据块的集合,如果是小数据量的数据丢失或损坏,而不是整个数据文件,这种类型的恢复是很有用的。通常,块损坏会在跟踪文件中报告错误信息。

块级别的数据丢失通常是由以下两个原因造成的:

n I/O错误引起的镜像数据丢失。

n 内存损坏,刷新到磁盘。

a.    使用RMAN BLOCKRECOVER命令的注意事项

n 目标数据库必须在MOUNT或者OPEN状态,如果执行某个数据文件的块介质恢复,那么该数据文件不能是脱机状态。

n 块介质恢复不支持基于时间点的块恢复。

n 只能在损坏的块上执行块介质恢复。

n 块被标记为介质损坏之后是不能访问的,直达恢复完成。

n 当使用备份的控制文件加载数据库时,不能执行块的介质恢复。

n 必须有一个包含损坏块文件的全备份,块介质恢复不能使用增量备份。

n 如果RMAN访问块介质恢复需要特定归档Redo日志文件失败,那么将执行还原FAILOVER,尝试使用RMAN资料库中列出的适合这个操作的所有其它备份,如果没有合适的备份存在执行才会失败。

n 数据文件头不能被恢复

n 不能在非归档模式下执行块介质恢复。

b.    RMAN BLOCKRECOVER命令的使用方式

RMAN BLOCKRECOVER命令有以下三种使用方式:

方式1 使用BLOCKRECOVER CORRUPTION LIST命令恢复在V$DATABASE_BLOCK_CORRUPTION视图中报告的所有块:

RMAN> blockrecover corruption list;

方式2 使用BLOCKRECOVER 命令的时候指定文件号和块号:

RMAN> blockrecover datafile block ;

方式3 执行blockrecover命令的时候指定表空间和数据块地址(DBA):

RMAN> blockrecover tablespace DBA ;

c.    RMAN BLOCKRECOVER使用的例子

例子1 恢复3个数据文件的损坏块:

RMAN> BLOCKRECOVER DATAFILE 2 BLOCK 12,13 DATAFILE 3 BLOCK 5,98,99 DATAFILE 4 BLOCK 19;

例子2:从数据文件拷贝中还原、恢复一系列块:

RMAN> RUN

{

BLOCKRECOVER DATAFILE 3 BLOCK 2,3,4,5 TABLESPACE sales DBA 4194405,4194409,4194412 from DATAFILECOPY;

}

例子3:从指定的tag备份总还原、恢复块

RMAN> BLOCKRECOVER TABLESPACE SYSTEM DBA 4194404,4194405 FROM TAG “weekly_backup”;

例子4:从用于恢复数据到两天以前的备份中还原、恢复SYSTEM表空间中的两个块:

RMAN> BLOCKRECOVER TALBESPACE SYSTEM DBA 4194404,4194405 RESOTRE UNTILL TIME ‘sysdate-2’;

例子5:运行备份验证数据库,修复在V$DATABASE_BLOCK_CORRUPTION中记录的所有损坏块:

RMAN> BACKUP VALIDATE DATABASE;

RMAN> BLOCKRECOVER CORRUPTION LIST;

1.3.4 确定损坏块对应的对象

确定损坏块对应的对象

要确定一个损坏的对象需要知道AFN(Absolute File Numbe,绝对文件号)BL(Block Number,块号)AFNRFNRelative File Number,相对文件号)通常是相同的,但是也可能不同(特别是如果数据库从Oracle7迁移或者如果使用的是可传输、可插拔的表空间),获得正确的AFNRFN就显得非常重要,如果指定了错误的AFN将导致找不到对象或错误识别对象。

a.    确定AFNBL

方法1:从ORA-1578得到AFN

ORA-1578之后产生的ORA-1110错误提供AFN号码。

方法2:从DBVERIFY输出获得AFN

通过使用DBV工具会报告损坏的块,DBV工具通过提供与相关的RDBARFNBL信息。

方法3:从RMAN获得AFN

RMANV$DATABASE_BLOCK_CORRUPTION视图报告损坏的块。该视图的字段FILE#表示AFN,字段BLOCK#表示BL

b.    定位损坏的对象

一旦AFN被识别,执行以下SQL语句定位损坏的对象:

SQL> select *

From DBA_EXTENTS

Where file_id=&AFN

And &BL BETWEEN BLOCK_ID AND BLOCK_ID + BLOCKS-1;

基于RMAN实现坏块介质恢复(blockrecover)

对于物理损坏的数据块,我们可以通过RMAN块介质恢复(BLOCK MEDIA RECOVERY)功能来完成受损块的恢复,而不需要恢复整个数据库或所有文件来修复这些少量受损的数据块。恢复整个数据库或数据文件那不是大炮用来打蚊子,有点不值得!但前提条件是你得有一个可用的RMAN备份存在,因此,无论何时备份就是一切。本文演示了产生坏块即使用RMAN实现坏块恢复的全过程。

1、创建演示环境

SQL> select * from v$version where rownum<2; 

 

BANNER 

-------------------------------------------------------------------------------- 

Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production 

 

--创建用于演示的data file 

SQL> create tablespace tbs_tmp datafile '/u02/database/usbo/oradata/tbs_tmp.dbf' size 10m autoextend on

 

SQL> conn scott/tiger; 

 

--基于新的数据文件创建对象tb_tmp 

SQL> create table tb_tmp tablespace tbs_tmp as select * from dba_objects; 

 

SQL> col file_name format a60 

SQL> select file_id,file_name from dba_data_files where tablespace_name='TBS_TMP'

 

   FILE_ID FILE_NAME 

---------- ------------------------------------------------------------ 

         6 /u02/database/usbo/oradata/tbs_tmp.dbf 

 

--表对象tb_tmp上的信息,包含对应的文件信息,头部块,总块数 

SQL> select segment_name , header_file , header_block,blocks       

  2  from dba_segments 

  3  where segment_name = 'TB_TMP' and owner='SCOTT'

 

SEGMENT_NAME                   HEADER_FILE HEADER_BLOCK     BLOCKS 

------------------------------ ----------- ------------ ---------- 

TB_TMP                                   6          130       1152 

 

--首先使用rman备份对应的数据文件 

$ $ORACLE_HOME/bin/rman target / 

RMAN> backup datafile 6 tag=health; 

 

Starting backup at 2013/08/28 17:03:15 

allocated channel: ORA_DISK_1 

channel ORA_DISK_1: SID=24 device type=DISK 

channel ORA_DISK_1: starting full datafile backup set 

channel ORA_DISK_1: specifying datafile(s) in backup set 

input datafile file number=00006 name=/u02/database/usbo/oradata/tbs_tmp.dbf 

channel ORA_DISK_1: starting piece 1 at 2013/08/28 17:03:16 

channel ORA_DISK_1: finished piece 1 at 2013/08/28 17:03:17 

piece handle=/u02/database/usbo/fr_area/USBO/backupset/2013_08_28/o1_mf_nnndf_HEALTH_91vh6ntb_.bkp tag=HEALTH comment=NONE 

channel ORA_DISK_1: backup set complete, elapsed time: 00:00:01 

Finished backup at 2013/08/28 17:03:17 

RMAN> exit 

2、单块数据块损坏的恢复处理

--下面使用了linux自带的dd命令来损坏单块数据块 

[oracle@linux1 ~]$ dd of=/u02/database/usbo/oradata/tbs_tmp.dbf bs=8192 conv=notrunc seek=130 <<eof  </eof  <>

> Corrupted block! 

> EOF 

0+1 records in 

0+1 records out 

17 bytes (17 B) copied, 0.000184519 seconds, 92.1 kB/s 

 

--清空buffer cache 

SQL> alter system flush buffer_cache; 

 

--查询表对相 tb_tmp,收到ORA-01578 

SQL> select count(*) from tb_tmp; 

select count(*) from tb_tmp 

ERROR at line 1: 

ORA-01578: ORACLE data block corrupted (file # 6, block # 130) 

ORA-01110: data file 6: '/u02/database/usbo/oradata/tbs_tmp.dbf' 

 

--查询视图v$database_block_corruption,提示有坏块,注意该视图可能不会返回任何数据,如无返回,先执行backup validate 

SQL> select * from v$database_block_corruption; 

 

     FILE#     BLOCK#     BLOCKS CORRUPTION_CHANGE# CORRUPTIO 

---------- ---------- ---------- ------------------ --------- 

         6        129          1                  0 CORRUPT 

 

--也可以使用dbv工具来校验坏块,参考: http://blog.csdn.net/robinson_0612/article/details/6530890     

 

--下面使用blockrecover来恢复坏块        

RMAN> blockrecover datafile 6 block 130; 

 

Starting recover at 2013/08/28 17:22:25 

using target database control file instead of recovery catalog 

allocated channel: ORA_DISK_1 

channel ORA_DISK_1: SID=24 device type=DISK 

 

channel ORA_DISK_1: restoring block(s) 

channel ORA_DISK_1: specifying block(s) to restore from backup set 

restoring blocks of datafile 00006 

channel ORA_DISK_1: reading from backup piece /u02/database/usbo/fr_area/USBO/backupset/2013_08_28/o1_mf_nnndf_HEALTH_91vh6ntb_.bkp 

channel ORA_DISK_1: piece handle=/u02/database/usbo/fr_area/USBO/backupset/2013_08_28/o1_mf_nnndf_HEALTH_91vh6ntb_.bkp tag=HEALTH 

channel ORA_DISK_1: restored block(s) from backup piece 1 

channel ORA_DISK_1: block restore complete, elapsed time: 00:00:01 

 

starting media recovery 

media recovery complete, elapsed time: 00:00:03 

 

Finished recover at 2013/08/28 17:22:31 

 

--再次查询表tb_emp正常 

SQL> select count(*) from tb_tmp; 

 

  COUNT(*) 

---------- 

     72449 

3、多块数据块损坏的恢复处理

--下面使用linux dd命令对不连续块损坏 

[oracle@linux1 ~]$ dd of=/u02/database/usbo/oradata/tbs_tmp.dbf bs=8192 conv=notrunc seek=133 <<eof  </eof  <>

> New corrupted block! 

> EOF 

0+1 records in 

0+1 records out 

21 bytes (21 B) copied, 0.000182835 seconds, 115 kB/s 

[oracle@linux1 ~]$ dd of=/u02/database/usbo/oradata/tbs_tmp.dbf bs=8192 conv=notrunc seek=143 <<eof   </eof   <>

> New corrupted block! 

> EOF 

0+1 records in 

0+1 records out 

21 bytes (21 B) copied, 0.000115527 seconds, 182 kB/s 

[oracle@linux1 ~]$ dd of=/u02/database/usbo/oradata/tbs_tmp.dbf bs=8192 conv=notrunc seek=153 <<eof   </eof   <>

> New corrupted block! 

> EOF 

0+1 records in 

0+1 records out 

21 bytes (21 B) copied, 0.000335781 seconds, 62.5 kB/s 

 

SQL> alter system flush buffer_cache; 

 

--下面提示块133被损坏,注意我们损坏了多块数据块,但查询时,从块号最小的开始提示,如133被修复后还有坏块则继续提示133之后的坏块 

SQL> select count(*) from scott.tb_tmp; 

select count(*) from scott.tb_tmp 

ERROR at line 1: 

ORA-01578: ORACLE data block corrupted (file # 6, block # 133) 

ORA-01110: data file 6: '/u02/database/usbo/oradata/tbs_tmp.dbf' 

 

--查询视图v$database_block_corruption无任何记录 

SQL> select * from v$database_block_corruption; 

 

no rows selected 

 

--下面使用backup validate来校验数据文件 

RMAN> backup validate datafile 6; 

 

Starting backup at 2013/08/29 09:42:04 

using target database control file instead of recovery catalog 

allocated channel: ORA_DISK_1 

channel ORA_DISK_1: SID=22 device type=DISK 

channel ORA_DISK_1: starting full datafile backup set 

channel ORA_DISK_1: specifying datafile(s) in backup set 

input datafile file number=00006 name=/u02/database/usbo/oradata/tbs_tmp.dbf 

channel ORA_DISK_1: backup set complete, elapsed time: 00:00:01 

List of Datafiles 

================= 

File Status Marked Corrupt Empty Blocks Blocks Examined High SCN 

---- ------ -------------- ------------ --------------- ---------- 

6    FAILED 0              223          1408            838489       --字段StatusFAILED 

  File Name: /u02/database/usbo/oradata/tbs_tmp.dbf 

  Block Type Blocks Failing Blocks Processed 

  ---------- -------------- ---------------- 

  Data       0              1029             

  Index      0              0                

  Other      3              156             --3Blocks Failing 

 

validate found one or more corrupt blocks 

See trace file /u02/database/usbo/diag/rdbms/usbo/usbo/trace/usbo_ora_27874.trc for details 

Finished backup at 2013/08/29 09:42:06 

--再次查询v$database_block_corruption,表明有3个损坏的块 

SQL> select * from v$database_block_corruption; 

 

     FILE#     BLOCK#     BLOCKS CORRUPTION_CHANGE# CORRUPTIO 

---------- ---------- ---------- ------------------ --------- 

         6        153          1                  0 CORRUPT 

         6        143          1                  0 CORRUPT 

         6        133          1                  0 CORRUPT 

 

--下面直接使用blockrecover corruption list来恢复,如下所有刚刚被校验的坏块都会被恢复 

RMAN> blockrecover corruption list;   

 

Starting recover at 2013/08/29 10:05:24 

using channel ORA_DISK_1 

 

channel ORA_DISK_1: restoring block(s) 

channel ORA_DISK_1: specifying block(s) to restore from backup set 

restoring blocks of datafile 00006 

channel ORA_DISK_1: reading from backup piece /u02/database/usbo/fr_area/USBO/backupset/2013_08_28/o1_mf_nnndf_HEALTH_91vh6ntb_.bkp 

channel ORA_DISK_1: piece handle=/u02/database/usbo/fr_area/USBO/backupset/2013_08_28/o1_mf_nnndf_HEALTH_91vh6ntb_.bkp tag=HEALTH 

channel ORA_DISK_1: restored block(s) from backup piece 1 

channel ORA_DISK_1: block restore complete, elapsed time: 00:00:01 

 

starting media recovery 

media recovery complete, elapsed time: 00:00:03 

 

Finished recover at 2013/08/29 10:05:28 

 

--校验结果 

SQL> select count(*) from scott.tb_tmp; 

 

  COUNT(*) 

---------- 

     72449 

4、坏块的对象定位与影响

--下面我们查询块号为163上的对象 

SQL> select dbms_rowid.rowid_object(rowid) object_id,dbms_rowid.rowid_relative_fno(rowid) file_id, 

  2  dbms_rowid.rowid_block_number(rowid) block_id,owner,object_name,object_id 

  3  from scott.tb_tmp where dbms_rowid.rowid_block_number(rowid)=163 and rownum<=2; 

 

 OBJECT_ID    FILE_ID   BLOCK_ID OWNER        OBJECT_NAME                     OBJECT_ID 

---------- ---------- ---------- ------------ ------------------------------ ---------- 

     74555          6        163 SYS          GV_$QUEUEING_MTH                     2439 

     74555          6        163 PUBLIC       GV$QUEUEING_MTH                      2440 

 

--使用上面的方法,我们损块块163173,此处不再列出 

 

a、对于坏块对象无法进行聚合汇总等操作      

SQL> select count(*) from scott.tb_tmp; 

select count(*) from scott.tb_tmp 

ERROR at line 1: 

ORA-01578: ORACLE data block corrupted (file # 6, block # 163) 

ORA-01110: data file 6: '/u02/database/usbo/oradata/tbs_tmp.dbf' 

 

b、对于坏块上的记录无法被查询 

--我们使用基于之前查询到的OBJECT_ID来查询 

SQL> select owner,object_name,object_id from scott.tb_tmp where object_id in(2439,2440); 

select owner,object_name,object_id from scott.tb_tmp where object_id in(2439,2440) 

                                              * 

ERROR at line 1: 

ORA-01578: ORACLE data block corrupted (file # 6, block # 163) 

ORA-01110: data file 6: '/u02/database/usbo/oradata/tbs_tmp.dbf' 

 

--如下面的查询,位于损坏块上的数据无法被查询到,但对于未损坏的依旧可以查询。下面的查询时块161上的对象 

SQL> select owner,object_name,object_id from scott.tb_tmp  

  2  where dbms_rowid.rowid_block_number(rowid)=161 and rownum<3; 

 

OWNER                          OBJECT_NAME                     OBJECT_ID 

------------------------------ ------------------------------ ---------- 

PUBLIC                         GV$RECOVERY_LOG                      2285 

SYS                            GV_$ARCHIVE_GAP                      2286 

 

--Author : Robinson Cheng 

--Blog   : http://blog.csdn.net/robinson_0612 

      

c、定位受损块所对应的对象 

SQL> run get_obj_name_from_corrupt_block 

  1  SELECT tablespace_name, 

  2         segment_type, 

  3         owner, 

  4         segment_name, 

  5         partition_name 

  6    FROM dba_extents 

  7*  WHERE file_id = &file_id AND &block_id BETWEEN block_id AND block_id + blocks - 1 

Enter value for file_id: 6 

Enter value for block_id: 133 

old   7:  WHERE file_id = &file_id AND &block_id BETWEEN block_id AND block_id + blocks - 1 

new   7:  WHERE file_id = 6 AND 133 BETWEEN block_id AND block_id + blocks - 1 

 

TABLESPACE_NAME                SEGMENT_TYPE       OWNER          SEGMENT_NAME      PARTITION_NAME 

------------------------------ ------------------ -------------- ----------------- ----------------- 

TBS_TMP                        TABLE              SCOTT          TB_TMP  

 

d、对于损坏的数据文件,缺省情况下,不能对其进行备份,如下 

RMAN> backup datafile 6 tag='corruption';                                                      

                                                                                                        

Starting backup at 2013/08/29 10:37:32                                                        

using channel ORA_DISK_1                                                                       

channel ORA_DISK_1: starting full datafile backup set                                         

channel ORA_DISK_1: specifying datafile(s) in backup set                                      

input datafile file number=00006 name=/u02/database/usbo/oradata/tbs_tmp.dbf                   

channel ORA_DISK_1: starting piece 1 at 2013/08/29 10:37:32                                   

RMAN-00571: ===========================================================                       

RMAN-00569: =============== ERROR MESSAGE STACK FOLLOWS ===============                       

RMAN-00571: ===========================================================                       

RMAN-03009: failure of backup command on ORA_DISK_1 channel at 08/29/2013 10:37:33            

ORA-19566: exceeded limit of 0 corrupt blocks for file /u02/database/usbo/oradata/tbs_tmp.dbf  

 

--需要设定允许损坏块的数量之后才能进行备份 

RMAN> run{ 

2> set maxcorrupt for datafile 6 to 2; 

3> backup datafile 6 tag='corruption'

4> } 

 

executing command: SET MAX CORRUPT 

 

Starting backup at 2013/08/29 10:41:24 

using channel ORA_DISK_1 

channel ORA_DISK_1: starting full datafile backup set 

channel ORA_DISK_1: specifying datafile(s) in backup set 

input datafile file number=00006 name=/u02/database/usbo/oradata/tbs_tmp.dbf 

channel ORA_DISK_1: starting piece 1 at 2013/08/29 10:41:25 

channel ORA_DISK_1: finished piece 1 at 2013/08/29 10:41:26 

piece handle=/u02/database/usbo/fr_area/USBO/backupset/2013_08_29/o1_mf_nnndf_CORRUPTION_91xf6o18_.bkp tag=CORRUPTION comment=NONE 

channel ORA_DISK_1: backup set complete, elapsed time: 00:00:01 

Finished backup at 2013/08/29 10:41:26        

 

--查看备份信息如下,应在修复坏块后重新备份以避免由于保留策略导致先前可用的备份被aged out 

RMAN> list backup summary; 

 

List of Backups 

=============== 

Key     TY LV S Device Type Completion Time     #Pieces #Copies Compressed Tag 

------- -- -- - ----------- ------------------- ------- ------- ---------- --- 

1       B  F  A DISK        2013/08/28 17:03:17 1       1       NO         HEALTH 

3       B  F  A DISK        2013/08/29 10:41:25 1       1       NO         CORRUPTION 

5、后记

a、对于受损的数据块,仅仅坏块上的数据无法被查询或读取,其余正常块的数据依旧可以使用。
b、对于受损的表对象进行聚合等相关运算时收到错误提示,因为坏块上的数据无法被统计。如果你聚合的是索引列,索引未损坏的情形则可正常返回。
c、可以基于RMAN可用的备份文件实现块介质恢复,其数据文件无需offline,开销最小,影响最小。
d、对于多个数据块的损坏,先执行backup validate校验数据库或相应的数据文件以便标记受损的坏块后,填充v$database_block_corruption以及后续恢复。
e、对于使用backup validate 校验后的情形,坏块恢复时可以直接使用blockrecover corruption list一次性恢复所有的坏块。
f、缺省情况下,存在坏块的数据文件无法成功备份,也会导致自动备份脚本失败。