处理Oracle数据库上的一个坏块(块没有被使用)

前几日检查一个生产环境库备份的时候发现了某个数据文件产生了逻辑坏块,检查该Corrupt block,上面并没有任何对象存在.
   对于这种情形的坏块,我们可以采用扩展extent的形式来格式化这些逻辑坏块,并配合一些细节上的处理技巧.
   以下是模拟案例.

案例描述:

(1)备份数据文件6,发现有坏块存在.

RMAN> backup datafile 6 format ‘E:\Backup\full_%s_%p’;
启动 backup 于 03-8月 -09
使用通道 ORA_DISK_1
通道 ORA_DISK_1: 启动全部数据文件备份集
通道 ORA_DISK_1: 正在指定备份集中的数据文件
输入数据文件 fno=00006 name=G:\ORACLE\MM01.DBF
通道 ORA_DISK_1: 正在启动段 1 于 03-8月 -09
RMAN-00569: =============== ERROR MESSAGE STACK FOLLOWS ===============
RMAN-00571: ===========================================================
RMAN-03009: backup 命令 (ORA_DISK_1 通道上, 在 08/03/2009 21:36:58 上) 失败
ORA-19566: 超出损坏块限制 0 (文件 G:\ORACLE\MM01.DBF)


(2)dbv检查
C:\>dbv file=G:\ORACLE\MM01.DBF blocksize=8192

DBVERIFY: Release 10.2.0.1.0 - Production on 星期一 8月 3 21:38:07 2009
Copyright (c) 1982, 2005, Oracle. All rights reserved.
DBVERIFY - 开始验证: FILE = G:\ORACLE\MM01.DBF
页 448000 标记为损坏
Corrupt block relative DBA: 0×0186d600 (file 6, block 448000)
Bad check value found during dbv:
Data in bad block:
type: 0 format: 2 rdba: 0×0006d600
last change scn: 0×0000.00000000 seq: 0×1 flg: 0×05
spare1: 0×0 spare2: 0×0 spare3: 0×0
consistency value in tail: 0×00000001
check value in block header: 0×7106
computed block checksum: 0×11

(3)坏块位于datafile 6 block 448000.查询该坏块上面的object.

SQL> select OWNER,SEGMENT_NAME from dba_extents a where file_id=6 and 448000 between a.block_id and a.block_id+a.blocks;

OWNER SEGMENT_NAME
—————————— ————-

SQL>select tablespace_name from dba_free_space where (448000 between block_id and block_id+blocks ) and file_id=6;

TABLESPACE_NAME
——————————
MM

   该block属于空闲block,并不存在任何对象.

处理过程

(1) 查询坏块所在datafile上已经分配的最大block.

SQL> select max(BLOCK_ID+blocks) from dba_extents a where tablespace_name=’MM’;
MAX(BLOCK_ID+BLOCKS)
——————–
46473

   当前已经分配的最大block为46473,而损坏的block位于448000,如果直接做数据填充推进extent,会产生较大的事务和redo量.为避免,我们可以创建2张表(本案例为tmp_1,tmp_2),一张表(tmp_1)用来推进extent到邻近损坏的block,使得后创建的一张表tmp2尽可能挨近坏块.然后对tmp_2做数据填充,用来格式化损坏的block.这样可以以消耗最少的redo代价和压力来完成format block的目的。
   同时,在需要填充的表上(tmp_2)创建触发器,当待处理坏块被格式化后,马上自动停止填充.
(2) 创建表tmp_1并推进extent

SQL> create table tmp_1 tablespace mm as select * from dba_data_files;
Table created

SQL> alter table tmp_1 allocate extent (datafile ‘g:\oracle\mm01.dbf’ size 3200M);
Table altered

SQL> select OWNER,SEGMENT_NAME from dba_extents a where file_id=6 and 448000 between a.block_id and a.block_id+a.blocks;

OWNER SEGMENT_NAME
—————————— ———–

(3)创建表tmp_2用以格式化坏块.

SQL> create table tmp_2(id number,text char(2000)) tablespace mm;
Table created

SQL> alter table tmp_2 allocate extent (datafile ‘g:\oracle\mm01.dbf’ size 200M);
Table altered

SQL> select OWNER,SEGMENT_NAME from dba_extents a where file_id=6 and 448000 between a.block_id and a.block_id+a.blocks;

OWNER SEGMENT_NAME
—————————— ————
REP TMP_2

   目前待扩充的表高水位线外已经包含坏块448000.

(4) 创建tmp_2上trigger,用于自动终止填充数据

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

(5) 推进HWM以格式化坏块

SQL>begin
loop
insert into tmp_2 values(1,rpad(’i',1800,’*'));
commit;
end loop;
end;
/
ORA-20001: curroption block format
ORA-06512: 在 “REP.TRIGGER_TRG_CURR_FIX”, line 6
ORA-04088: 触发器 ‘REP.TRIGGER_TRG_CURR_FIX’ 执行过程中出错
ORA-06512: 在 line 3

   至此,填充自动终止,坏块已经被格式化.做几次日志切换,然后用dbv再次检查数据文件,发现已经修复.接下来删除表tmp_1和tmp_2.
标签: 暂无标签
oraunix

写了 199 篇文章,拥有财富 1026,被 339 人关注

转播转播 分享分享 分享淘帖
回复

使用道具

P4 | 发表于 2010-11-21 05:57:11
本帖最后由 kevin.zhang 于 2010-11-21 05:58 编辑

填充法修复未分配到的坏块的方法早就有了,但是利用allocate extent减少redo和工作量是亮点,很实用!特别是在生产环境中。
回复

使用道具

P3 | 发表于 2010-11-29 13:28:56
老师说的很详细,可是看不懂。
回复

使用道具

您需要登录后才可以回帖 登录 | 加入社区

本版积分规则

意见
反馈