数据文件出现坏快的解决之一(如何利用dbms_repair来标记和跳过坏块)

数据文件出现坏快的解决之一(如何利用dbms_repair来标记和跳过坏块)

http://blog.chinaunix.net/u1/50863/showart_400574.html

 

第一步:准备试验环境(建表空间,用户,表,初始化一些数据,然后破坏对应的数据文件)

E:\Oracle\ora92\bin>sqlplus "/ as sysdba"

SQL*Plus: Release 9.2.0.4.0 - Production on 星期一 3月 8 20:27:15 2004

Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.


连接到:
Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.4.0 - Production

SQL> select name from v$datafile;

NAME
--------------------------------------------------------------------------------
E:\ORACLE\ORADATA\oracle92\SYSTEM01.DBF
E:\ORACLE\ORADATA\oracle92\UNDOTBS01.DBF
E:\ORACLE\ORADATA\oracle92\app01.DBF

grant dba to test1107;

SQL> create tablespace block datafile 'd:\oracle\oradata\block.dbf' size 2M;
表空间已创建。
SQL> create user test1107 identified by aaaa default tablespace block;
用户已创建
SQL> conn test1107/aaaa;
已连接。
SQL> create table test tablespace block as select * from all_tables;
表已创建。
SQL> insert into test select * from test;
已创建8行。
SQL> /
已创建16行。
SQL> /
已创建32行。
SQL> /
已创建64行。
SQL> /
已创建128行。
SQL> /
已创建256行。
SQL> /
已创建512行。
SQL> /
已创建1024行。
SQL> /
已创建2048行。
SQL> /
已创建4096行。
SQL> /
insert into test select * from test
*
ERROR 位于第 1 行:
ORA-01653: 表test1107.TEST无法通过8(在表空间BLOCK中)扩展

SQL> create index i_test on test(table_name);

Index created

SQL> alter system checkpoint;

System altered

SQL> connect sys/sys as sysdba
已连接。
SQL> shutdown immediate
数据库已经关闭。
已经卸载数据库。
ORACLE 例程已经关闭。

--使用UltraEdit编辑block.dbf,修改几个字符

SQL> startup
ORACLE 例程已经启动。

Total System Global Area   72424008 bytes
Fixed Size                   453192 bytes
Variable Size              46137344 bytes
Database Buffers           25165824 bytes
Redo Buffers                 667648 bytes
数据库装载完毕。
数据库已经打开。
QL> select count(*) from test1107.test;

select count(*) from test1107.test

ORA-01578: ORACLE 数据块损坏(文件号13,块号9)
ORA-01110: 数据文件 13: 'D:\ORACLE\ORADATA\BLOCK.DBF'

 

第二步:利用dbv检查数据文件

dbv file='d:\oracle\ora92\block.dbf' blocksize=8192 logfile='d:\work\temp\dbv.log'
  日志:
   DBVERIFY - 验证完成

   检查的页总数         :256
   处理的页总数(数据):112
   失败的页总数(数据):0
   处理的页总数(索引):17
   失败的页总数(索引):0
   处理的页总数(其它):10
   处理的总页数 (段)  : 0
   失败的总页数 (段)  : 0
   空的页总数            :102
   标记为损坏的总页数:15
   汇入的页总数           :0


第三步:利用dbms_repair包进行处理
1.创建管理表:
SQL> connect sys/sys as sysdba
Connected to Oracle9i Enterprise Edition Release 9.2.0.1.0
Connected as SYS

SQL> exec DBMS_REPAIR.ADMIN_TABLES('REPAIR_TABLE',1,1,'USERS');

PL/SQL procedure successfully completed

SQL> exec DBMS_REPAIR.ADMIN_TABLES('ORPHAN_TABLE',2,1,'USERS');

PL/SQL procedure successfully completed

2.检查坏块:

 declare
    cc number;
 begin
    dbms_repair.check_object(schema_name => 'TEST1107',object_name => 'TEST',corrupt_count => cc);
    dbms_output.put_line(a => to_char(cc));
 end;

 15

PL/SQL 过程已成功完成。     

看到这里用dbms_repair.check,检查的结果corrupt_count=15,有15个块损坏,和dbv的结果一致。

check完之后,在我们刚在创建的REPAIR_TABLE中查看块损坏信息:   

SQL> SELECT * from repair_table
在这个table中,可以看到损坏的block的信息,这里的信息和我们用dbv得到的一致。
我这个实验是在9i下模拟的,注意看MARKED_CORRUPT的值,这里经过check_object后,已经标识为TRUE了。
所以可以直接进行第四步了。按照oracle文档上的说法,在8i下,check_object只会检查坏块,MARKED_CORRUPT为false需要使用第3步,fix_corrupt_blocks定位 ,修改MARKED_CORRUPT为true,同时更新CHECK_TIMESTAMP。
这里我们经过实验,确认在9i下跳过第3步,是完全可行的。那么8i是否需要执行第三步,我没有实验过,但推测应该是不可以跳过的。  

3.定位坏块:

dbms_repair.fix_corrupt_blocks     

只有将坏块信息写入定义的REPAIR_TABLE后,才能定位坏块。 
declare
  cc number;
begin
  dbms_repair.fix_corrupt_blocks(schema_name => 'TEST1107',object_name => 'TEST',fix_count => cc);
  dbms_output.put_line(a => to_char(cc));
end;

4.跳过坏块:

我们前面虽然定位了坏块,但是,如果我们访问table还是会得到错误信息。   
这里需要用skip_corrupt_blocks来跳过坏块:

SQL> exec dbms_repair.skip_corrupt_blocks(schema_name => 'TEST1107',object_name => 'TEST',flags => 1);

PL/SQL procedure successfully completed

SQL> select count(*) from test1107.test;

  COUNT(*)
----------
      4490

 

5.处理index上的无效键值;

SQL> declare
  2  cc number;
  3  begin
  4  dbms_repair.dump_orphan_keys(schema_name => 'TEST1107',object_name => 'I_TEST',object_type => 2,
  5  repair_table_name => 'REPAIR_TABLE',orphan_table_name => 'ORPHAN_TABLE',key_count => CC);
  6  end;
  7  /

PL/SQL procedure successfully completed

SQL> SELECT * FROM ORPHAN_TABLE;

22 rows selected

表示损失了22行数据

我们根据这个结果来考虑是否需要rebuild index.

 

6.重建freelist:rebuild_freelists

SQL> exec dbms_repair.rebuild_freelists(schema_name => 'TEST1107',object_name => 'TEST');

PL/SQL procedure successfully completed

你可能感兴趣的:(数据文件出现坏快的解决之一(如何利用dbms_repair来标记和跳过坏块))