首页 > 数据库 > Oracle > Oracle数据块损坏的应急处理
DBA 最不想接到的一类告警是 ORA-01578: ORACLE data block corrupted。它意味着某个数据块物理损坏,访问到这个块的查询和 DML 全部失败,而同一个表里其他块上的数据看起来完好无损。此时如果备份齐全,首选 RMAN 块介质恢复(RECOVER ... BLOCK 或 BACKUP VALIDATE 后按 V$DATABASE_BLOCK_CORRUPTION 清单恢复),块内容可以真正还原;但在没有可用块备份、或业务等不及恢复窗口的场合,就需要另一个工具:DBMS_REPAIR。
DBMS_REPAIR 不修复数据,它的定位是止损与抢救:检测损坏块并登记、把损坏块标记为软件损坏(soft corrupt)使对象恢复可用、让扫描跳过坏块、导出指向坏块的索引键以便后续重建数据。
先明确权限:该包属于 SYS,EXECUTE 权限不授予其他用户,所有操作以 SYSDBA 身份执行 。
应急流程涉及五个子程序:
-- 创建/清理登记表
DBMS_REPAIR .ADMIN_TABLES (
table_name IN VARCHAR2 ,
table_type IN BINARY_INTEGER , -- REPAIR_TABLE / ORPHAN_TABLE
action IN BINARY_INTEGER , -- CREATE_ACTION / PURGE_ACTION / DROP_ACTION
tablespace IN VARCHAR2 DEFAULT NULL ) ;
-- 检查对象,损坏信息登记到 repair table
DBMS_REPAIR .CHECK_OBJECT (
schema_name IN VARCHAR2 ,
object_name IN VARCHAR2 ,
partition_name IN VARCHAR2 DEFAULT NULL ,
object_type IN BINARY_INTEGER DEFAULT TABLE_OBJECT ,
repair_table_name IN VARCHAR2 DEFAULT 'REPAIR_TABLE' ,
relative_fno IN BINARY_INTEGER DEFAULT NULL ,
block_start IN BINARY_INTEGER DEFAULT NULL ,
block_end IN BINARY_INTEGER DEFAULT NULL ,
corrupt_count OUT BINARY_INTEGER ) ;
-- 将已登记的损坏块标记为软件损坏
DBMS_REPAIR .FIX_CORRUPT_BLOCKS (
schema_name IN VARCHAR2 ,
object_name IN VARCHAR2 ,
partition_name IN VARCHAR2 DEFAULT NULL ,
object_type IN BINARY_INTEGER DEFAULT TABLE_OBJECT ,
repair_table_name IN VARCHAR2 DEFAULT 'REPAIR_TABLE' ,
fix_count OUT BINARY_INTEGER ) ;
-- 设置扫描时跳过软件损坏块
DBMS_REPAIR .SKIP_CORRUPT_BLOCKS (
schema_name IN VARCHAR2 ,
object_name IN VARCHAR2 ,
object_type IN BINARY_INTEGER DEFAULT TABLE_OBJECT ,
flags IN BINARY_INTEGER DEFAULT SKIP_FLAG ) ;
-- 导出指向坏块的索引键
DBMS_REPAIR .DUMP_ORPHAN_KEYS (
schema_name IN VARCHAR2 ,
object_name IN VARCHAR2 ,
partition_name IN VARCHAR2 DEFAULT NULL ,
object_type IN BINARY_INTEGER DEFAULT INDEX_OBJECT ,
repair_table_name IN VARCHAR2 DEFAULT 'REPAIR_TABLE' ,
orphan_table_name IN VARCHAR2 DEFAULT 'ORPHAN_KEYS_TABLE' ,
key_count OUT BINARY_INTEGER ) ;
CHECK_OBJECT 还支持 relative_fno 加 block_start/block_end 传入块区间,只检查可疑范围,不必每次全表扫描。
两个登记表的说明:ADMIN_TABLES 默认创建 REPAIR_TABLE(坏块登记表)和 ORPHAN_KEYS_TABLE(孤儿键登记表),自建同用途表必须以 REPAIR_ 或 ORPHAN_ 前缀命名。CREATE 时会同时在 SYS 下生成对应的 DBA_ 视图。
各步骤在流程中的作用:
| 子程序 | 作用 |
|---|---|
| CHECK_OBJECT | 逐块校验对象,坏块写入 REPAIR_TABLE,corrupt_count 返回坏块数 |
| FIX_CORRUPT_BLOCKS | 按 REPAIR_TABLE 的登记把坏块标记为软件损坏(标记前会再校验一次),数据不恢复 |
| SKIP_CORRUPT_BLOCKS | flags 传 SKIP_FLAG 后,表和索引扫描跳过软件损坏块;NOSKIP_FLAG 恢复报 ORA-01578 的默认行为 |
| DUMP_ORPHAN_KEYS | 把索引中指向坏块行的键值导出到孤儿键表,是事后补数据的关键线索 |
坏块无法用常规 SQL 人为制造(一般借助 bbed 之类的工具改块,属于破坏性实验,只应在可随意丢弃的测试库做),因此这里在健康对象上把建表和检查两个步骤完整走一遍,确认流程与输出形态;真实故障时的后续步骤在第三节给出完整处置顺序。
1. 创建登记表(SYS)
SQL > exec dbms_repair .admin_tables ( 'REPAIR_TABLE' , -
> dbms_repair .repair_table , dbms_repair .create_action )
PL/SQL procedure successfully completed.
SQL > exec dbms_repair .admin_tables ( 'ORPHAN_KEYS_TABLE' , -
> dbms_repair .orphan_table , dbms_repair .create_action )
PL/SQL procedure successfully completed.
2. 对 TEST 用户的表执行检查(SYS)
SQL > set serveroutput on
SQL > declare
2 v_count number ;
3 begin
4 dbms_repair .check_object (
5 schema_name => 'TEST' ,
6 object_name => 'T_SPACE' ,
7 corrupt_count => v_count ) ;
8 dbms_output .put_line ( 'corrupt blocks = ' || v_count ) ;
9 end ;
10 /
corrupt blocks = 0
PL/SQL procedure successfully completed.
健康表检查结果为 0,REPAIR_TABLE 中也没有新登记。检查一个中型段的代价与全表扫描相当,生产上应安排在业务低峰。
3. 登记表的结构(SYS)
SQL> desc repair_table
Name Type
----------------------------- ----------------------------
REPAIR_ID NUMBER
OBJECT_ID NUMBER
TABLESPACE_ID NUMBER
RELATIVE_FILE_ID NUMBER
BLOCK_ID NUMBER
CORRUPT_TYPE NUMBER
SCHEMA_NAME VARCHAR2(30)
OBJECT_NAME VARCHAR2(30)
BASEOBJECT_NAME VARCHAR2(30)
PARTITION_NAME VARCHAR2(30)
CORRUPT_DESCRIPTION VARCHAR2(2000)
REPAIR_DESCRIPTION VARCHAR2(200)
MARKED_CORRUPT VARCHAR2(10)
CHECK_TIMESTAMP DATE
FIX_TIMESTAMP DATE
真实损坏发生后,每行对应一个坏块,CORRUPT_TYPE 给出损坏类别,REPAIR_DESCRIPTION 是建议的处理动作(如 mark block software corrupt),MARKED_CORRUPT 记录是否已执行标记 。
以下是一套完整的应急处置流程(SYS,均在低峰执行):
1. 定位与登记 。用 RMAN VALIDATE 或 BACKUP VALIDATE CHECK LOGICAL 扫出坏块清单(V$DATABASE_BLOCK_CORRUPTION) ,先确认有备份则直接走块介质恢复;无备份才继续:
declare
v_count number ;
begin
dbms_repair .check_object (
schema_name => 'TEST' ,
object_name => 'T_SPACE' ,
corrupt_count => v_count ) ;
dbms_output .put_line ( 'corrupt blocks = ' || v_count ) ;
end ;
/
2. 标记软件损坏 。把坏块封存,防止读操作碰到物理损坏造成连锁问题:
declare
v_fix number ;
begin
dbms_repair .fix_corrupt_blocks (
schema_name => 'TEST' ,
object_name => 'T_SPACE' ,
fix_count => v_fix ) ;
dbms_output .put_line ( 'blocks fixed = ' || v_fix ) ;
end ;
/
3. 让扫描跳过坏块 。此后全表扫描不再报 ORA-01578,只是静默少掉坏块上的数据:
SQL > exec dbms_repair .skip_corrupt_blocks ( -
> 'TEST' , 'T_SPACE' , dbms_repair .table_object , dbms_repair .skip_flag )
PL/SQL procedure successfully completed.
4. 导出孤儿键 。对表上的每个索引执行,为补数据留底:
declare
v_keys number ;
begin
dbms_repair .dump_orphan_keys (
schema_name => 'TEST' ,
object_name => 'IDX_T_SPACE_ID' ,
object_type => dbms_repair .index_object ,
orphan_table_name => 'ORPHAN_KEYS_TABLE' ,
key_count => v_keys ) ;
dbms_output .put_line ( 'orphan keys = ' || v_keys ) ;
end ;
/
5. 抢救与重建 。从孤儿键表(含索引键值)与其他来源尽量还原坏块中的行,重建受影响索引;数据补齐评估完成后,重建表段(CTAS 或 MOVE)彻底离开坏块,再联系原厂或按平台手段处理底层存储问题。
FIX_CORRUPT_BLOCKS 只是标记,不恢复任何数据;每标记一个块,该块上所有行丢失(除非从别处补回)。这一步执行前应完成一切可行的数据抢救评估;
SKIP_CORRUPT_BLOCKS 对索引生效的范围有限制:索引范围扫描只跳过损坏的非根叶子块,根块或分支块损坏的索引无法靠跳过维持可用,必须重建;
启用跳过后查询不再报错,坏块上的行会"无声消失,count(*) 与业务对账可能出现差异,事后要凭孤儿键表和日志核对;
REPAIR_TABLE 的登记不会自动清理,重复处理前用 ADMIN_TABLES 的 PURGE_ACTION 清空旧记录,避免 FIX 环节读到过期登记;
坏块的根因往往在存储层(磁盘坏道、控制器、双写不一致),DBMS_REPAIR 只处理数据库层的表象,底层问题不解决,坏块还会再现。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70013625/viewspace-3184267/ ,如需转载,请注明出处,否则将追究法律责任。