BLOCKRECOVER是修复ORA-1578/ORA-26040单块损坏的唯一有效命令,依赖归档日志或RMAN备份定位并重刷坏块,但不自动清理V$DATABASE_BLOCK_CORRUPTION视图,需手动验证。
ORA-1578 / ORA-26040 错误出现时,BLOCKRECOVER 是唯一能救活单块的命令
oracle 数据文件里某个块坏了,select 报 ora-1578(数据块损坏),dbverify 或告警日志里看到 ora-26040(使用了 nologging 操作后介质恢复失败),这时候别急着 restore 整个 datafile——blockrecover 就是专治这种“局部坏块”的手术刀。
它不依赖完整备份,只要归档日志链完整、或者有 RMAN 备份 + 归档,就能只拉取那个坏块对应时间点的镜像重刷进去。前提是:坏块没在系统关键对象(如 SYSTEM 表空间的回滚段头块)上,否则会报错退出。
- 必须用 RMAN 连接目标库(
CONNECT TARGET /),不能用 SQL*Plus 直接调 - 坏块号得从
V$DATABASE_BLOCK_CORRUPTION或告警日志里抠出来,格式是file# block#,比如5 12345 - 如果没开 Flashback Database,且归档不全,
BLOCKRECOVER会直接失败,提示找不到所需归档,这时只能 restore datafile
RMAN 中执行 BLOCKRECOVER 的三种写法区别在哪
不是所有写法都等价。RMAN 支持按块号、按对象、按备份集指定恢复范围,但底层行为和容错能力不同:
-
BLOCKRECOVER DATAFILE 5 BLOCK 12345;—— 最常用,精准定位,但要求该块当前确实被标记为 corrupt(即存在于V$DATABASE_BLOCK_CORRUPTION),否则报RMAN-06571:no corrupt blocks found -
BLOCKRECOVER TABLESPACE users;—— 扫描整个表空间找坏块再恢复,适合批量修复,但耗时长,且可能把已人工修复的块又覆盖回去 -
BLOCKRECOVER CORRUPTION LIST;—— 只对V$DATABASE_BLOCK_CORRUPTION里当前存在的条目生效,适合脚本化批量处理,但不会自动刷新视图内容(需先ANALYZE TABLE ... VALIDATE STRUCTURE CASCADE或运行DBMS_REPAIR.CHECK_OBJECT)
注意:BLOCKRECOVER 默认走归档日志应用,不触发 full backup restore;但如果归档缺失,它会悄悄 fallback 到最近可用的 level 0 备份 + 归档组合——这个切换不报错,但恢复时间可能陡增。
坏块在索引上还能用 BLOCKRECOVER 吗?小心索引分裂导致二次损坏
可以,但风险比堆表高。索引块损坏常伴随逻辑不一致(比如兄弟块指针错乱),BLOCKRECOVER 只管物理替换,不管逻辑自洽。
典型现象:恢复完索引块,下次 INSERT 或 UPDATE 触发分裂时突然报 ORA-00600 [kdxlin: bad block type]——说明旧索引结构已腐坏,单块恢复只是暂时掩盖问题。
- 优先跑
ANALYZE INDEX ... VALIDATE STRUCTURE ONLINE;确认是否仅物理损坏 - 若验证失败,别硬 recover,直接
ALTER INDEX ... REBUILD ONLINE;更安全 - 重建前记得查
DBA_INDEXES.UNIQUENESS和STATUS,避免 rebuild 失败卡住 DML
BLOCKRECOVER 成功后,坏块还在 V$DATABASE_BLOCK_CORRUPTION 里?
这是最常被忽略的点:RMAN 完成恢复后,V$DATABASE_BLOCK_CORRUPTION 不会自动清空。视图内容只由 BACKUP VALIDATE、RESTORE VALIDATE 或 DBVERIFY 主动扫描时写入,不是实时状态镜像。
所以你看到“恢复成功”但视图里还有记录,不代表没修好——而是没人重新扫描确认。真正验证方式只有两个:
- 对对应对象执行
SELECT /*+ FULL */ COUNT(*) FROM ...,看是否还报 ORA-1578 - 手动运行
RMAN> BACKUP VALIDATE CHECK LOGICAL DATABASE;,之后再查视图
别信视图里的“残留”,也别信 RMAN 输出的 “completed successfully” 就万事大吉;IO 层缓存、ASM diskgroup rebalance 延迟、甚至 storage array 的 write cache 未刷盘,都可能导致坏块看似消失实则还在磁盘暗处等着下次读取时爆发。

















