Oracle数据文件的每个块,其块头为20字节。其定义如下:(来自于DSI401)
在块头中,seq_kcbh(占用1字节,块头偏移14)有着特殊的含义,如果该值为0xff,则表示该块被标记为corruption。
下面我们做一个测试:
修改db_block_checksum参数值为TRUE,关闭数据库,我们用ultraedit修改10号文件的1447块的check sum(一个随便>0的数)及flag=0×04。然后再打开数据库。再执行下面的查询:
由于非系统表空间在db_block_checksum参数设为FALSE时,会忽略checksum的检查。所以这里为了测试的方便设置为TRUE。
从上面的错误信息来看,块号1447这个块已经坏了,报的错误是经典的ORA-01578错误。
我们用dbv检查一下这个文件:
dbv检查发现了坏块(check错误)。
而如果用analyze命令检查也会发现有坏块:
我们用dbms_repair来处理这个坏块(实际上如果只是checksum坏了,可以修改checksum为正确的值。但实际情况下,checksum坏了往往意味着坏内的数据已经坏了,大多数情况下只能丢弃):
从上面可以看到,dbms_repair.fix_corrupt_blocks并不修复checksum错误,也不做坏块标记。通过dbv和用ultraedit检查块头,没有发现任何变化。但是通过dbms_repair.skip_corrupt_blocks过程在数据字典中将表设置为跳过坏块,则在查询时会跳过该块。
如果用RMAN备份该文件,而后还原该文件后,则这个坏块的seq_kcbh则被设为0xff。而此时用dbv 查该文件则显示的错误信息则为:
注意这里“标记为损坏的总页数”跟前一次检查的不一样,这里为“0”。
注意,使用skip_corrupt_blocks只能使oracle跳过Oracle能够读出的块,而如果在操作系统层read调用就失败的,则不能跳过该过。甚至于该会话也可能会被中断。遇到这样的情况,使用dd命令或操作系统的copy(cp)命令都不能复制该文件,rman也不能备份该文件,遇到这样的问题,如果数据文件没有备份怎么办?
在前几天我们的一个客户就遇上了这样的问题,windows系统,2节点RAC,使用了OCFS,由于存储及硬盘出现问题,1个数据文件出现坏块,连操作系统都不能复制出该文件。这样的情况在前几个月也遇到过,不过那个系统是Linux系统下的RAC(难不成OCFS的问题?二者都用了OCFS)。由于存储出了问题,硬盘亮了黄灯,换盘之后故障仍然存在。需要紧急备份这个库,但是那个文件始终无法复制出来。
遇到这样的情况,写个脚本把数据插入到另一个表?然后exp出来?到现场发现,那个坏块所在的表,居然有200G以上。有没有更简单的方法?到了客户那里,我利用大约20多分钟的时间,写了个简单的程序来复制这个不能利用操作系统工具复制出来的文件。其原理就是以块为单位读取数据,写入一个新的文件中,遇到读不出来的块,就写个一坏块(seq_kcbh设为0xff,flag_kcbh设为0×04,checksum就随便写入一个值,其他全为0)到新文件中。这样就复制出来了文件,幸运的是,整个文件复制其坏块只有2个。经过测试该文件完全可用。