数据库 频道

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

数据库出现坏块在我干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,用它可以跳过坏块遍历某张表。通过这个把数据导出到一张新表里。不过这种方式把坏块中的行全部丢弃了,对于关键业务数据来说存在数据丢失的风险。为了尽可能多的导出数据,可以再辅以上面的方法,通过适当的索引扫描,把坏块中的数据行找出来,把恢复工作做得更加完善。

0
相关文章