问题描述 
日常数据库巡检,发现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; 
 
反思 
数据库检查出坏块不要慌,先搞清楚坏的是表还是索引,索引的话重建就完事,表的话可能得牺牲点数据,不过一切都建立在数据库没备份的情况下!  |