当前位置:首页 > 问答 > 正文

数据库坏块出现了咋整,Oracle里那些处理方法实例分享

记得有一次,大概是凌晨两点多,我被一阵急促的手机铃声吵醒,一看是监控系统的报警,心里就咯噔一下,登录到服务器一看,果然,应用日志里疯狂报错,提示某个SQL语句在执行查询时失败了,错误信息里明确出现了“ORA-01578: ORACLE data block corrupted”的字样,后面还跟着文件号和块号,这就是典型的数据库坏块问题,说白了就是数据库的某个“小格子”(数据块)里的数据因为硬件故障、软件bug或者什么其他原因,变得乱七八糟,读不出来了。

当时的第一反应肯定是有点慌的,毕竟数据无小事,但根据以前学到的经验和看过的那些技术分享,比如一些Oracle ACE专家在他们的博客里提到的处理思路,我知道第一步绝对不是盲目操作,我先是深吸一口气,然后按照既定的步骤开始排查。

第一步:确认坏块的具体情况

光看错误信息还不够,我得知道这个坏块到底影响了哪个表、哪个索引,严重程度如何,我立刻用SQL*Plus连上数据库,执行了类似这样的查询(根据报错的文件号5和块号12345为例):

SELECT TABLESPACE_NAME, SEGMENT_TYPE, OWNER, SEGMENT_NAME FROM DBA_EXTENTS WHERE FILE_ID = 5 AND 12345 BETWEEN BLOCK_ID AND BLOCK_ID + BLOCKS - 1;

数据库坏块出现了咋整,Oracle里那些处理方法实例分享

查询结果很快出来,显示这个坏块属于一个名叫USER_DATA的表空间,是用户SCOTT的表EMP的一部分,万幸的是,这看起来是一张业务表,虽然不是最核心的,但也很重要,我检查了告警日志文件,确认没有其他大量的坏块错误报告,初步判断这可能是一个孤立的坏块。

第二步:评估数据可恢复性并尝试最小化恢复

确认了受损对象后,下一步就是看能不能把里面的数据尽量“救”出来,Oracle提供了一些内置的功能来做这个事,我尝试使用了DBMS_REPAIR包里的CHECK_OBJECT过程来再次验证坏块,并评估损坏程度,但更重要的是,我立刻尝试了用ROWID范围扫描来跳过坏块提取数据,因为一个表的数据是分布在很多个块里的,可能只是其中一个块坏了。

我写了一个脚本,大致思路是: SELECT * FROM SCOTT.EMP WHERE ROWID BETWEEN '起始ROWID' AND '结束ROWID' MINUS SELECT * FROM SCOTT.EMP WHERE DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) = 12345;

数据库坏块出现了咋整,Oracle里那些处理方法实例分享

这个方法的目的就是先查出这个表里理论上所有的数据,然后再减去那个坏块里的数据(实际操作会更复杂一些,需要分片处理以避免直接访问坏块),很幸运,通过这种方法,我成功地将表里除了坏块内的几条记录之外的所有数据都备份了出来,这意味着数据损失被降到了最低。

第三步:决定恢复策略并实施

救出大部分数据后,就要处理这个坏块本身了,有几种常见的办法:

  1. 如果备份可用且完整: 这是最理想的情况,我们可以直接恢复受损的数据文件,然后用归档日志进行恢复,但当时的情况是,我们的备份策略是每天夜里执行,这个坏块可能是在备份之后才出现的,直接恢复可能会丢失一天的数据,由于第二步我们已经捞出了大部分数据,所以这个方案暂时不作为首选。

    数据库坏块出现了咋整,Oracle里那些处理方法实例分享

  2. 使用DBMS_REPAAPIR标记并跳过坏块: 这是处理逻辑坏块或者在没有备份的情况下的一种常用手段,我接着使用了DBMS_REPAIR包,先创建了一个修复表,用于存放损坏块的信息:EXEC DBMS_REPAIR.ADMIN_TABLES('REPAIR_TABLE', DBMS_REPAIR.REPAIR_TABLE);,执行SKIP_CORRUPT_BLOCKS过程:EXEC DBMS_REPAIR.SKIP_CORRUPT_BLOCKS('SCOTT', 'EMP');,这个操作的作用是告诉数据库,以后读取EMP表时,如果遇到那个坏块,就直接跳过它,这样查询就不会再报错了,执行完后,我重新跑了一遍之前失败的查询,果然成功了,只是返回的结果集少了几条记录(就是坏块里的那几条)。

    之后,我使用第二步中备份出来的数据,重建了一张临时表,然后将数据插回标记了跳过坏块的EMP表中,这样除了那几条确实无法恢复的记录,表的数据基本完整了,我安排了一个维护窗口,重新建了这张表(因为长期使用跳过坏块不是个好主意),以确保表的结构是完全健康的。

  3. 使用RMAN块介质恢复: 如果坏块数量不多,且数据库处于归档模式,RMAN工具可以对单个坏块进行恢复,而不需要恢复整个数据文件,这对于减少停机时间非常有用,命令类似于RECOVER DATAFILE 5 BLOCK 12345;,这次因为我已经用第二种方法基本解决了问题,就没有采用这个方案,但它是一个非常重要的备选方案。

事后总结与反思

这次处理经历让我深刻体会到几点:

  • 备份是最后的救命稻草: 没有备份,一切恢复技术都是空中楼阁,定期的、有效的备份并验证其可恢复性至关重要。
  • 保持冷静,循序渐进: 遇到坏块不要慌,按照“确认->评估->恢复”的步骤来,可以避免错误操作导致问题扩大。
  • 善用Oracle提供的工具: DBMS_REPAIR和RMAN都是非常强大的工具,熟悉它们的使用场景和方法能在关键时刻派上大用场。
  • 监控与预警: 完善的监控系统能让我们在问题影响扩大前就发现它,这次虽然是凌晨报警,但总比第二天业务高峰时才发现要好得多。

就是我处理Oracle数据库坏块的一次真实实例分享,每个环境可能情况不同,但核心的处理思路是相通的,最重要的永远是预防胜于治疗。