记录一次坏块不在任何segment上的处理过程

客户在做RMAN备份的时候总是报错,于是客户用DBV校验了文件,发现有坏块.因为以前都做过RMAN备份,刚刚做就出现这类的问题.于是就叫我们去解决.以下是这个问题的解决步骤:

R:\oracle\hisdb>dbv file=DLSYY BLOCKSIZE=8192
DBVERIFY: Release 10.2.0.1.0 - Production on 星期一 5月 21 21:02:08

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

DBVERIFY - 开始验证: FILE = DLSYY
页 3334278 标记为损坏
Corrupt block relative dba: 0x0172e086 (file 5, block 3334278)
Bad check value found during dbv:
Data in bad block:
type: 6 format: 2 rdba: 0x0172e086
last change scn: 0x0000.1d6e043f seq: 0x3 flg: 0x06
spare1: 0x0 spare2: 0x0 spare3: 0x0
consistency value in tail: 0x043f0603
check value in block header: 0xc478
computed block checksum: 0x800

DBVERIFY - 验证完成

检查的页总数: 4194302
处理的页总数 (数据): 2195170
失败的页总数 (数据): 0
处理的页总数 (索引): 1961275
失败的页总数 (索引): 0
处理的页总数 (其它): 32789
处理的总页数 (段)  : 0
失败的总页数 (段)  : 0
空的页总数: 5067
标记为损坏的总页数: 1
流入的页总数: 0
最高块 SCN            : 691673568 (0.691673568)

可以看到坏块的位置在块3334278上面.我们查询这个块所在地对象,可以看到是在表IP_MDREQUEST_BAK上面.

SQL> select *from V$DATABASE_BLOCK_CORRUPTION;
FILE#     BLOCK#     BLOCKS CORRUPTION_CHANGE# CORRUPTIO
---------- ---------- ---------- ------------------ ---------
5    3334278          1                  0 CHECKSUM

SQL> select segment_name,SEGMENT_TYPE from dba_extents where FILE_ID=5
2     and 3334278 between BLOCK_ID and BLOCK_ID+BLOCKS-1;

SEGMENT_NAME                                                                               SEGMENT_TYPE
--------------------------------------------------------------------------                 -----------------
IP_MDREQUEST_BAK                                                                           TABLE

SQL> drop table dlsyy.IP_MDREQUEST_BAK purge;

表已删除。

把这个表删除了之后,然后再次做DBV校验,发现还是有坏块,坏块的位置还在刚才那个块上,此时查询,这个块不在任何segment上面.

SQL> select segment_name,SEGMENT_TYPE from dba_extents where FILE_ID=5
2   and 3334278 between BLOCK_ID and BLOCK_ID+BLOCKS-1;
未选定行

解决办法:

1.此时这个块应该只是checksum坏了,我们只需要把checksum修改成正确的值就行了.

2.建一个新的表,给这个表插入数据,一直到插入到坏的块报错为止.

这里我选择了使用第二种方法来解决这个问题.

SQL> create table test tablespace DLSYY as select * from dba_data_files;
表已创建。

建完表后,我们可以使用下列循环来扩展这个表的尺寸.因为我们默认建完表分配都是64K.所以下面是用64K来扩展这个表.在扩展到同时,我们去开一个会话去监控坏块所处的对象,如果坏块进入到了当前所建的对象,我们就可以终止该循环语句.

BEGIN
for i in 1..1000000 loop
EXECUTE IMMEDIATE 'alter table test allocate extent (DATAFILE '||'''R:\ORACLE\HISDB\DLSYY||'SIZE 64K) ';
end loop;
end ;
/
SQL> select segment_name,SEGMENT_TYPE from dba_extents where FILE_ID=5
2    and 3334278 between BLOCK_ID and BLOCK_ID+BLOCKS-1;

SEGMENT_NAME                                                               SEGMENT_TYPE
-------------------------------------------------------------------------- -----------------
TEST                                                                       TABLE

[注]:关闭数据文件的自动扩展属性.

接下来我们建立一个触发器,当我们插入数据,如果到达了块3334278的时候,就抛出一个异常,

create or replace trigger trigger_trg_curr_fix after insert on test for each row
declare
nblock_id number;
begin
select dbms_rowid.rowid_block_number(:new.rowid) into nblock_id from dual;
if nblock_id=3334278 then
raise_application_error(-20001,'curroption block format');
end if;
end;

最后我们就多开几个session来循环执行插入,当到达触发器所在地块号的时候,就抛出了异常,此时我们的块就被我们格式化掉了.

SQL>begin
for i in 1..100000000 loop
for j in 1..1000 loop
insert into test(FILE_NAME,FILE_ID,TABLESPACE_NAME) values('SSSSSSSSSSSSSSS',i,'xXXXXXXXXXXX');
end loop;
commit;
end loop;
end;
/

再一次使用DBV校验工具进行校验,坏块消失,备份正常!

R:\oracle\hisdb>dbv file=DLSYY blocksize=8192
DBVERIFY: Release 10.2.0.1.0 - Production on 星期一 5月 21 22:36:53 2012

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

DBVERIFY - 开始验证: FILE = DLSYY

DBVERIFY - 验证完成

检查的页总数: 4194302
处理的页总数 (数据): 2218006
失败的页总数 (数据): 0
处理的页总数 (索引): 1938676
失败的页总数 (索引): 0
处理的页总数 (其它): 32553
处理的总页数 (段)  : 0
失败的总页数 (段)  : 0
空的页总数: 5067
标记为损坏的总页数: 0
流入的页总数: 0
最高块 SCN            : 692302023 (0.692302023)

参考文档:

How to Format Corrupted Block Not Part of Any Segment [ID 336133.1]

分享到: 更多

Post a Comment

Your email is never published nor shared. Required fields are marked *