ITPub博客

首页 > 数据库 > Oracle > Oracle数据块损坏的应急处理

Oracle数据块损坏的应急处理

原创 Oracle 作者:a960549548 时间:2026-09-29 14:06:41 0 删除 编辑

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)彻底离开坏块,再联系原厂或按平台手段处理底层存储问题。

四、注意事项

  1. FIX_CORRUPT_BLOCKS 只是标记,不恢复任何数据;每标记一个块,该块上所有行丢失(除非从别处补回)。这一步执行前应完成一切可行的数据抢救评估;

  2. SKIP_CORRUPT_BLOCKS 对索引生效的范围有限制:索引范围扫描只跳过损坏的非根叶子块,根块或分支块损坏的索引无法靠跳过维持可用,必须重建;

  3. 启用跳过后查询不再报错,坏块上的行会"无声消失,count(*) 与业务对账可能出现差异,事后要凭孤儿键表和日志核对;

  4. REPAIR_TABLE 的登记不会自动清理,重复处理前用 ADMIN_TABLES 的 PURGE_ACTION 清空旧记录,避免 FIX 环节读到过期登记;

  5. 坏块的根因往往在存储层(磁盘坏道、控制器、双写不一致),DBMS_REPAIR 只处理数据库层的表象,底层问题不解决,坏块还会再现。


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70013625/viewspace-3184267/ ,如需转载,请注明出处,否则将追究法律责任。

下一篇: 没有了~
请登录后发表评论 登录
全部评论
Oracle ACE,MySQL 8.0 OCP,PMP,拥有OceanBase OBCP,TiDB PCTP,GoldenDB GDCP等多项认证,ITPUB认证专家,微信公众号:DBA之友。

注册时间:2022-02-08

  • 博文量
    132
  • 访问量
    171498