ITPub博客

首页 > 数据库 > Oracle > 记一次业务表数据损坏场景下的灾难挽救案例分析

记一次业务表数据损坏场景下的灾难挽救案例分析

原创 Oracle 作者:龙山游龙 时间:2025-01-06 16:23:26 0 删除 编辑

1 、故障描述

某次某用户由于存储硬件故障,导致数据库无法正常启动。该故障影响了一个大小为22GB的数据文件,存储损坏后,文件只能读取到 20.4GB ,且无法进行正常恢复。尽管存储层面进行了修复,数据库依然无法启动,导致出现一系列数据损坏及恢复问题。

2 、根因分析

前期处理步骤,如下表所示:

步骤

关键点

说明

Step1

Undo   段屏蔽及表空间更换

在初步诊断后,针对损坏的 undo 段进行了屏蔽,并更换了受影响的 undo 表空间,以避免对数据库其他部分的影响

Step2

坏块修复

通过数据库坏块修复工具,定位并修复了损坏的数据块,同时删除了受损坏的数据对象的索引

Step3

设置了部分隐含参数

例如一致性校验、undo回滚段、events等

Step4

打开数据库

做了一系列调整之后,数据库正常启动

Step5

全库逻辑导出

为了确保数据不丢失,开始执行全库的逻辑导出操作。然而,在导出 `XXUSER.XXTAB_OLD` 表时出现了错误,改用exp依然报错

 

在导出 `XXUSER.XXTAB_OLD` 表时, ORA-01555 报错,并提示该表存在损坏的数据块。该表为本次数据恢复的核心表,原表共计约 13 万条数据。以下为错误详情:

1. 使用 `select * from XXUSER.XXTAB_OLD;` 查询数据时,发现表中存在损坏的记录,导致无法完整查询表中的数据。

 


2. 尝试使用 `create table` 语句创建新表时,系统报错,并提示无法创建。通过限制查询条件为 `rownum` ,可以成功创建新表,但仅能插入最多 79000 条记录。超过 79000 后的记录无法成功插入。

 


3. 进一步打印所有的 `rowid` 后,发现表中 79000 条记录之后存在损坏的部分数据。但仍有部分记录是完好的,可以被查询。通过以下查询验证损坏与完好的数据:

   Select * from XXUSER.XXTAB_OLD where rowid='XXXXXXXX';

   查询结果显示, 79000 条记录后存在部分损坏的记录。

为了解决数据损坏问题,采取了以下恢复措施:

1. 创建新表:

   使用以下 SQL 语句创建新表:

   create table XXUSER.table2024(TEXTID varchar2(500), ROWTEXT varchar2(500));

 

2. 插入完好数据:

   通过原表中所有数据行的 rownum, rowid 插入到 table2024 中:

   insert into XXUSER.table2024

   select rownum, rowid

   from XXUSER.XXTAB_OLD;

   commit;

 

3. 创建新表的表结构:

   创建新的表 `XXUSER.XXTAB_NEW2024` ,无数据,该表作为数据恢复的落地表:

CREATE TABLE XXUSER.XXTAB_NEW2024 AS SELECT * FROM XXUSER.XXTAB_OLD WHERE 1=0;

 

4. 使用存储过程清洗数据:

   编写存储过程 `TAB_insert` 来过滤掉损坏的记录,只插入可查询的数据:

CREATE OR REPLACE PROCEDURE TAB_insert

AS

  cursor tab_cur is

    SELECT TEXTID,ROWTEXT FROM XXUSER.table2024;

begin

  for tab_recoder in tab_cur loop

  begin

    insert into XXUSER.XXTAB_NEW2024 select PART_ID,UNIT_ID,STOCK_ID,PART_NAME,STOCK_NUM,BAD_NUM,GIVE_NUM,IN_PRICE,ACTUAL_PRICE,TOTAL_PRICE,TAX_RATE,TAXES_PRICE,STOCK_PLACE,MIN_STOCK_NUM,MAX_STOCK_NUM,MEMO from  XXUSER.XXTAB_OLD where rowid = tab_recoder.ROWTEXT;

    commit;

    EXCEPTION WHEN others THEN null;

  end;

  end loop;

end;

/

execute tab_insert();

 


新表的数据量为 138823 ,故障表的数据量为 138928 ,成功最大程度的恢复数据,只缺失了 105 条记录;

相关 MOS 参考文档, Extract rows from a CORRUPT table creating ROWID from DBA_EXTENTS (Doc ID 422547.1)

3 、解决思路

1. 硬件故障排查及修复:客户的外置存储硬件故障已经修复,因此数据库故障的根本原因已得到解决。

2. 数据库启动恢复:通过修复坏块、屏蔽损坏的 undo 段和调整表空间,恢复了数据库的正常启动和运行。

3. 数据损坏恢复:通过 `rowid` 抽取和存储过程的方式,成功将完好的数据从损坏的数据表中提取,并恢复到了新的表中。


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

请登录后发表评论 登录
全部评论
传统商业、开源和国产据库领域十从业经验,TB级高并发数据库的管理经验。对于数据库内部原理、体系结构,数据页/块结构原理有着深刻认识;对于数据库新特性、分布式高可用架构和性能调优有着丰富的的实战经验。擅长故障诊断以及数据库异常打开及数据灾难挽救。

注册时间:2015-06-28

  • 博文量
    178
  • 访问量
    334708