Oracle DBMS_REPAIR 修复损坏块

Oracle DBMS_REPAIR 修复损坏块

适用版本:Oracle Database 8i / 9i / 10g / 11g / 12c / 19c / 23ai 文档版本:v1.0 / 2026-07


1. 概述

DBMS_REPAIR 包用于检测和修复数据块损坏[1]:

核心功能

  • 检测损坏块
  • 标记损坏块
  • 跳过损坏块
  • 重建空闲列表

限制

  • 不能恢复损坏块中的数据
  • 仅让数据库继续运行

2. 检测损坏块

2.1 RMAN 检测

-- 1. RMAN 验证
RMAN> BACKUP VALIDATE CHECK LOGICAL DATABASE;

-- 2. 查看损坏
SELECT * FROM v$database_block_corruption;

2.2 DBV 工具

# 验证数据文件
dbv file=/u01/oradata/orcl/users01.dbf blocksize=8192

# 输出示例:
# DBVERIFY: Verification complete
# Total Pages Examined         : 12800
# Total Pages Processed (Data) : 10000
# Total Pages Failing   (Data) : 5

2.3 ANALYZE 验证

-- 验证表
ANALYZE TABLE scott.employees VALIDATE STRUCTURE;

-- 验证索引
ANALYZE INDEX scott.emp_idx VALIDATE STRUCTURE;

3. DBMS_REPAIR 流程

3.1 创建修复表

-- 1. 创建修复表
BEGIN
  DBMS_REPAIR.ADMIN_TABLES(
    table_name => 'REPAIR_TABLE',
    table_type => DBMS_REPAIR.REPAIR_TABLE,
    action => DBMS_REPAIR.CREATE_ACTION,
    tablespace => 'USERS'
  );
END;
/

-- 2. 创建孤立项表
BEGIN
  DBMS_REPAIR.ADMIN_TABLES(
    table_name => 'ORPHAN_TABLE',
    table_type => DBMS_REPAIR.ORPHAN_TABLE,
    action => DBMS_REPAIR.CREATE_ACTION,
    tablespace => 'USERS'
  );
END;
/

3.2 检测损坏

-- 检测损坏对象
SET SERVEROUTPUT ON
DECLARE
  num_corrupt INT;
BEGIN
  DBMS_REPAIR.CHECK_OBJECT(
    schema_name => 'SCOTT',
    object_name => 'EMPLOYEES',
    repair_table_name => 'REPAIR_TABLE',
    corrupt_count => num_corrupt
  );
  DBMS_OUTPUT.PUT_LINE('Number corrupt: ' || num_corrupt);
END;
/

3.3 查看损坏

-- 查看损坏块
SELECT 
  object_name,
  block_id,
  corrupt_type,
  marked_corrupt
FROM repair_table;

3.4 标记损坏块

-- 标记为损坏
SET SERVEROUTPUT ON
DECLARE
  num_fix INT;
BEGIN
  DBMS_REPAIR.FIX_CORRUPT_BLOCKS(
    schema_name => 'SCOTT',
    object_name => 'EMPLOYEES',
    object_type => DBMS_REPAIR.TABLE_OBJECT,
    repair_table_name => 'REPAIR_TABLE',
    fix_count => num_fix
  );
  DBMS_OUTPUT.PUT_LINE('Number fix: ' || num_fix);
END;
/

3.5 跳过损坏块

-- 设置跳过损坏块
BEGIN
  DBMS_REPAIR.SKIP_CORRUPT_BLOCKS(
    schema_name => 'SCOTT',
    object_name => 'EMPLOYEES',
    object_type => DBMS_REPAIR.TABLE_OBJECT,
    flags => DBMS_REPAIR.SKIP_FLAG
  );
END;
/

-- 取消跳过
BEGIN
  DBMS_REPAIR.SKIP_CORRUPT_BLOCKS(
    schema_name => 'SCOTT',
    object_name => 'EMPLOYEES',
    object_type => DBMS_REPAIR.TABLE_OBJECT,
    flags => DBMS_REPAIR.NOSKIP_FLAG
  );
END;
/

3.6 重建空闲列表

-- 重建 FREELISTS
BEGIN
  DBMS_REPAIR.REBUILD_FREELISTS(
    schema_name => 'SCOTT',
    object_name => 'EMPLOYEES',
    object_type => DBMS_REPAIR.TABLE_OBJECT
  );
END;
/

3.7 查找孤立项

-- 查找索引中的孤立项
SET SERVEROUTPUT ON
DECLARE
  num_orphan INT;
BEGIN
  DBMS_REPAIR.DUMP_ORPHAN_KEYS(
    schema_name => 'SCOTT',
    object_name => 'EMP_IDX',
    object_type => DBMS_REPAIR.INDEX_OBJECT,
    repair_table_name => 'REPAIR_TABLE',
    orphan_table_name => 'ORPHAN_TABLE',
    key_count => num_orphan
  );
  DBMS_OUTPUT.PUT_LINE('Number orphan: ' || num_orphan);
END;
/

4. 块介质恢复(BMR)

4.1 RMAN BMR

-- 1. 查看损坏块
SELECT * FROM v$database_block_corruption;

-- 2. 恢复单个块
RMAN> RECOVER DATAFILE 5 BLOCK 123;

-- 3. 恢复所有损坏块
RMAN> RECOVER CORRUPTION LIST;

4.2 BMR 优势

  • 在线恢复
  • 仅恢复损坏块
  • 业务影响最小
  • 无需关闭数据库

5. 损坏块处理流程

1. 检测损坏块
   - RMAN VALIDATE
   - DBV
   - ANALYZE

2. 评估损坏
   - 查询 repair_table
   - 确定影响范围

3. 尝试 BMR
   - RMAN RECOVER
   - 优先使用

4. 若 BMR 失败
   - DBMS_REPAIR.FIX_CORRUPT_BLOCKS
   - DBMS_REPAIR.SKIP_CORRUPT_BLOCKS

5. 恢复数据
   - 从备份恢复
   - 从其他源补充
   - 重建索引

6. 验证
   - 再次检测
   - 业务验证

6. 常见场景

6.1 单块损坏

-- 1. BMR 恢复
RMAN> RECOVER DATAFILE 5 BLOCK 123;

-- 2. 验证
SELECT * FROM scott.employees WHERE rowid = DBMS_ROWID.ROWID_CREATE(1, 5, 123, 0, 0);

6.2 多块损坏

-- 1. 查看所有损坏
SELECT * FROM v$database_block_corruption;

-- 2. 批量恢复
RMAN> RECOVER CORRUPTION LIST;

6.3 索引损坏

-- 1. 重建索引
ALTER INDEX scott.emp_idx REBUILD;

-- 2. 验证
ANALYZE INDEX scott.emp_idx VALIDATE STRUCTURE;

7. 监控损坏

7.1 v$database_block_corruption

SELECT 
  file#,
  block#,
  blocks,
  corruption_change#,
  corruption_type
FROM v$database_block_corruption;

7.2 corruption_type

类型说明
ALL ZERO块全零
FRACTURED块头不匹配
CHECKSUM校验和错误
CORRUPT损坏
LOGICAL逻辑损坏

7.3 Alert Log

# 监控 alert log 中的 ORA-01578
grep "ORA-01578" $ORACLE_BASE/diag/rdbms/$DB_UNIQUE_NAME/$ORACLE_SID/trace/alert_$ORACLE_SID.log

8. 常见坑与排错

8.1 ORA-01578: 数据块损坏

修复

-- 1. 查看损坏块
SELECT * FROM v$database_block_corruption;

-- 2. BMR 恢复
RMAN> RECOVER DATAFILE <file#> BLOCK <block#>;

-- 3. 或使用 DBMS_REPAIR

8.2 ORA-00600: 内部错误

修复

# 1. 查看 trace 文件
cat $ORACLE_BASE/diag/rdbms/$DB_UNIQUE_NAME/$ORACLE_SID/trace/*ora*.trc

# 2. 联系 Oracle Support
# 3. 提供错误参数和 trace

8.3 BMR 失败

修复

-- 1. 检查备份
RMAN> LIST BACKUP OF DATAFILE 5;

-- 2. 使用 DBMS_REPAIR
-- 3. 从其他源恢复数据

8.4 损坏块数据丢失

修复

-- 1. 从备份恢复部分数据
-- 2. 从其他系统补充
-- 3. 重建索引
ALTER INDEX scott.emp_idx REBUILD;

8.5 跳过损坏块后查询异常

修复

-- 1. 检查跳过状态
SELECT owner, table_name, skip_corrupt 
FROM dba_tables 
WHERE owner='SCOTT' AND table_name='EMPLOYEES';

-- 2. 取消跳过(恢复后)
BEGIN
  DBMS_REPAIR.SKIP_CORRUPT_BLOCKS(
    schema_name => 'SCOTT',
    object_name => 'EMPLOYEES',
    object_type => DBMS_REPAIR.TABLE_OBJECT,
    flags => DBMS_REPAIR.NOSKIP_FLAG
  );
END;
/

9. 最佳实践

  1. 优先 BMR:RMAN RECOVER
  2. BMR 失败用 DBMS_REPAIR:标记跳过
  3. 定期 RMAN VALIDATE:检测损坏
  4. 监控 v$database_block_corruption:及时发现
  5. 备份关键表:数据保护
  6. 重建索引:损坏后修复
  7. 联系 Oracle Support:严重问题
  8. 测试恢复:验证流程
  9. 保留 trace 文件:分析原因
  10. 硬件检查:底层问题

10. 参考资料

[1] Oracle Database Administrator’s Guide 19c, “DBMS_REPAIR” https://docs.oracle.com/en/database/oracle/oracle-database/19/admin/

[2] Oracle Database PL/SQL Packages and Types Reference 19c, “DBMS_REPAIR” https://docs.oracle.com/en/database/oracle/oracle-database/19/arpls/