查看原文
其他

一个简单易用的数据库坏块处理方案

白鳝 白鳝的洞穴
2024-09-30

         

 

数据库出现坏块在我干DBA的时候是常见的事情,处理各种各样坏块的案例可能经历过上百个。很多情况下坏块问题可通过数据库恢复来完成,像Oracle早就支持块级恢复,因此现在Oracle出坏块,只要有备份,通过块级恢复就可以了。如果有ADG那就更简单了,通过ADG的文件恢复就可以了。

今天介绍的一个方法不仅可以在Oracle数据库上使用,也可以用于其他数据库。当数据库缺少可用备份或者不支持块级恢复,一张表出现一个坏块要恢复整个数据库比较麻烦的场景。处理方法比较简单,就是跳过坏的数据,把其他数据写入一张临时性的表,然后将存在坏块的表rename成old表,再把临时性的表rename成生产表就可以了。下面我们看这个案例。

因为某种不可言状的问题,用户的某张十分重要的表出现了访问问题。访问这张表的应用报错ORA-08103。通过客户端去访问这张表也是报同样的错误。

在该表的某个extent中,高水位下有个BLOCK对应的type是错误的,当对该表进行扫描或者访问到某个记录的时候,访问到这种块就会出现ORA-8103报错,操作无法正常进行。如果存在这种形式的坏块,无法对表进行全表扫描,也无法将该表exp出来。    

通过对该表的检查,发现坏块的rdba是:72/13283,检查结果如下:

 这个坏块中共有13条记录,当访问到这13条记录的时候就会出现ORA-8103错误。遇到这种问题,简单地通过dbms_repair去修复坏块是不行的,因为ORA-8103说明在高水位下遇到了一个rdba上看不输于这个段的块。通过bbed修改rdba后再来做repair是可行的,不过对于DBA的要求比较高。实际上遇到这样的问题其实有一种十分通用的简单解决方法,这个方法不仅对Oracle数据库有效,对大多数开源国产数据库同样有效。该方案有以下几个步骤:

1)首先创建一张表结构完全一致的表,比如new_temp表。    
2)创建一张存储损坏行行号的临时表

3)找到一个该表的包含所有行的索引,比如主键或者非空字段上的索引,只要是能包含所有数据行就可以了。如果不存在这样的索引,那么就会稍微麻烦一些,要找到一种能够按照行遍历整个表的方法。
4)编写一个存储过程或者JAVA/PYTHON等程序来完成数据导出。


set serveroutput on

declare

  nrows number;

  badrows number;

  VYHDABH VARCHAR2(50);

  VFGSBH  VARCHAR2(50);

  VJBH    VARCHAR2(50);

begin

 badrows:=0;    

 nrows:=0;

 for i in (select /*+ index (tab1) */ rowid,FGSBH from 有故障的表 tab1) loop

  begin

   insert into  newtb select   * 

   from 有故障的表 where rowid=i.rowid;

   if (mod(nrows,20000)=0) then 

     commit;

   end if;

exception when others then

   badrows:=badrows+1;

   //找到所有的该表的索引,尽可能把能找到的列数据都找出来

   //写入BADROWS表里,尽可能多地恢复数据

   select /*+ index(a YH_DNB_IND_2)  */ yhdabh,FGSBH,JBH 

     into VYHDABH,VFGSBH,VJBH 

   from ld_data.yh_dnb a 

   where rowid=i.rowid;

   insert into bad_rows values (i.Rowid,VFGSBH,VYHDABH,VJBH);

   commit;

  end;

  nrows:=nrows+1;

 end loop;

 dbms_output.put_line('Total rows: '||to_char(nrows)||' Bad rows: '||to_char(badrows));    

 Commit;

end;

/


5)将原表rename 为Old
6)将临时表rename为原表
7)给新表添加索引与授权


在上面的这个案例中,这个坏块中一共存在13条记录,把这十三条记录的用户档案号也都找到了,于是恢复后只需要补录这十三条记录,整个数据就恢复了。

这个方法可以使用于其他数据库上,特别是段页式存储结构的数据库,比如达梦、神通Oscar等。PostgreSQL数据库有一个参数:zero_damaged_pages,用它可以跳过坏块遍历某张表。通过这个把数据导出到一张新表里。不过这种方式把坏块中的行全部丢弃了,对于关键业务数据来说存在数据丢失的风险。为了尽可能多的导出数据,可以再辅以上面的方法,通过适当的索引扫描,把坏块中的数据行找出来,把恢复工作做得更加完善。

         

 

   

继续滑动看下一个
白鳝的洞穴
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存