| 问题描述日常数据库巡检,发现Alert日志提示ORA-01578:Oracle数据库损坏 (文件号 10,块号 28732);
 
 排查步骤
 
 1、找出所有受影响的数据库对象
 select tablespace_name, segment_type, owner,segment_name  from dba_extents
 where file_id = 10 and 28732 between block_idAND block_id + blocks - 1;
 
 查询可得,受影响的数据库对象为t_test , 类型为table
 
 2、 查询受坏块影响的对象
 查询表对应的索引信息。
 SQL> select owner, index_name, index_typefrom dba_indexes
 where table_owner='test' ANDtable_name='t_test';
 
 查询主键约束条件。
 SQL> select owner, constraint_name,constraint_type, table_name from dba_constraints
 WHERE owner='test' ANDconstraint_name='&INDEX_NAME' AND constraint_type='P';
 
 3、通过plsql 查询与表相关的触发器和视图,并对创建语句做好备份
 
   
 解决步骤
 Step a
 利用dbms_repair包,先创建repair table两个表:
 begin
 dbms_repair.admin_tables(
 table_name=>'REPAIR_TABLE',
 table_type=>dbms_repair.repair_table,
 action=>dbms_repair.create_action,
 tablespace=>'ts_test');
 end;
 /
 
 begin
 dbms_repair.admin_tables(
 table_type=>dbms_repair.orphan_table,
 action=>dbms_repair.create_action,
 tablespace=>'ts_test');
 end;
 /
 
 Step b
 校验受损的对象
 set serveroutput on
 declare
 rpr_count int;
 begin
 rpr_count:=0;
 dbms_repair.check_object(
 schema_name=>'test',
 object_name=>'t_test',
 repair_table_name=>'REPAIR_TABLE',
 corrupt_count=>rpr_count);
 dbms_output.put_line('repaircount:'||to_char(rpr_count));
 end;
 /
 repair count:1
 
 Step c
 下面的查询中可以看出列marked_corrupt全部为true,表明我们在check_object过程中已经标注了坏块
 
 SQL> select object_name,block_id,corrupt_type,marked_corrupt,corrupt_description,repair_descriptionfrom repair_table;
 
 OBJECT_NAM   BLOCK_ID CORRUPT_TYPEMARKED_COR CORRUPT_DESCRIP REPAIR_DESCRIPTION
 ---------- ---------- ------------ ------------------------- ------------------------------
 t_test              27632        6148 TRUE                      mark block software corrupt
 
 Step d
 忽略坏块
 exec dbms_repair.skip_corrupt_blocks(schema_name=> 'test',object_name => 't_test',flags =>dbms_repair.skip_flag );
 
 PL/SQL procedure successfully completed.
 
 Step e
 通过hint强制count(*) 走全表扫描,执行结果无报错,统计结果对比之前,坏块导致表t_test数据丢失了3行。
 
   Select /* full(t_test)*/ count(*) from t_test;
 
 反思
 数据库检查出坏块不要慌,先搞清楚坏的是表还是索引,索引的话重建就完事,表的话可能得牺牲点数据,不过一切都建立在数据库没备份的情况下!
 |