测试环境:11.2.0.4
1.1 创建测试表
1.2 查询表中每一行对应的文件号和块号
1.3 使用bbed工具模拟破坏6号数据文件的3893数据块
关于bbed的编译和使用可参考
1.3.1 准备bbed配置文件:
编辑/tmp/bbed.par参数配置文件
由于bbed不能直接操作ASM里面的数据文件,所以需把对应的数据文件转储出来:
测试调用bbed正常:
1.3.2 破坏数据文件6的3893数据块
1.3.3 使用dbv检查文件
数据库有有效的RMAN备份,那么很简单,直接恢复损害数据块即可。
RMAN> blockrecover datafile 6 block 3893;
常规恢复输出类似下面这样:
恢复完成后可以正常访问。
3.1 查看AFN和RFN
获取普通文件的AFN和RFN:
select tablespace_name, file_id "AFN", relative_fno "RFN" from dba_data_files;
注意:实验发现,大文件表空间的RFN固定为1024。
获取临时文件的AFN和RFN:
select tablespace_name, file_id + value "AFN", relative_fno "RFN" from dba_temp_files, v$parameter where name = 'db_files';
3.2 创建 REPAIR_TABLE 和 ORPHAN_KEY_TABLE
REPAIR_TABLE用来记录错误检查结果,ORPHAN_KEY_TABLE用来记录表坏块中记录在索引中对应键值。
3.3 使用CHECK_OBJECT过程检测坏块
执行结果:
如果marked_corrupt不是true,则需要使用fix_corrupt_blocks过程修复:
这里实验此步骤执行不执行都可以。
3.4 使用DUMP_ORPHAN_KEYS过程来保存坏块中的索引键值
select object_name, block_id, marked_corrupt from repair_table;
select index_name from dba_indexes where table_name in (select distinct object_name from repair_table);
这时还存在着一个潜在的问题。
就是表有坏块,但索引没有损坏,通过表扫描会出现错误,但是通过索引扫描仍然可以返回结果,这会造成数据的不一致性。
比如,这里我知道id = 4的记录:
使用DUMP_ORPHAN_KEYS过程来保存坏块中的索引键值:
执行结果如下:
这样当之后执行完SKIP_CORRUPT_BLOCKS操作后,就可以重新建立索引了(对每个索引都要执行DUMP_ORPHAN_KEYS过程)。
3.5 使用skip_corrupt_blocks过程来跳过坏块
执行skip_corrupt_blocks过程,使后续DML操作跳过坏块:
执行结果:
3.6 重建freelist
如果不想使用CTAS方式重建表而仍是在原表上修复,则需要重建对象的Freelist,防止这个数据块以后被加到freelist中。使用下面的方法:
这里实际已知坏块不在freelist中,所以不需要执行,执行会报错如下错误:
3.7 重建索引
目前索引和数据块仍然存在不一致,必须要重建索引:
当然,如果此时使用dbv检查数据文件,依然是有坏块的,上面所有操作只是跳过坏块,并没有解决。
善后工作(与数据块恢复无关):
养成一个习惯,做任何实验,如果对实验环境改动较大,建议实验完毕后,尽量恢复到正常状态,避免今后测试其他案例时现修复环境。
我这里就是把实验环境恢复(6号文件恢复为原来的ASM存储上):
至此,已完成数据块恢复实例的整个实验。
此外,针对坏块问题,还有一种方式是设置10231 event,具体可参考: