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