Oracle坏块处理之dbms_repair的用法

 

1、模拟坏块

SQL> create tablespace test01 datafile 'G:oracleproduct10.2.0oradataora10gtest01.dbf' size 1m;

表空间已创建。

SQL> create table test(id number,name varchar2(30)) tablespace test01;

表已创建。

SQL> insert into test select rownum,object_name from dba_objects;

insert into test select rownum,object_name from dba_objects

*

第 1 行出现错误:

ORA-01653: 表 SYS.TEST 无法通过 8 (在表空间 TEST01 中) 扩展

SQL> insert into test select rownum,object_name from dba_objects where rownum<10000;

已创建9999行。

SQL> commit;

提交完成。

SQL> insert into test select rownum,object_name from dba_objects where rownum<10000;

已创建9999行。

SQL> commit;

提交完成。

SQL> select count(*) from test;

COUNT(*)

----------

19998

SQL> create index id_inx on test(id);

索引已创建。

SQL> create index name_inx on test(name);

索引已创建。

SQL> shutdown immediate

数据库已经关闭。

已经卸载数据库。

ORACLE 例程已经关闭。

然后使用UltraEdit等工具编辑数据文件,修改里面的部分内容。

SQL> startup

ORACLE 例程已经启动。

数据库装载完毕。

数据库已经打开。

SQL> select count(*) from test;

select count(*) from test

*

第 1 行出现错误:

ORA-01578: ORACLE 数据块损坏 (文件号 7, 块号 19)

ORA-01110: 数据文件 7: 'G:ORACLEPRODUCT10.2.0ORADATAORA10GTEST01.DBF'

可见我们已经模拟出坏块的情景。

2、使用analyze table 或DBV检测坏块的信息

SQL> analyze table test validate structure;

analyze table test validate structure

*

第 1 行出现错误:

ORA-01578: ORACLE 数据块损坏 (文件号 7, 块号 19)

ORA-01110: 数据文件 7: 'G:ORACLEPRODUCT10.2.0ORADATAORA10GTEST01.DBF'

通过对表进行analyze之后,该表的相关坏块信息会写入到跟踪文件中,我们可以通过脚本获得此跟踪文件:

SQL> @G:oracleget_trace.sql;

TRACE_FILE

--------------------------------------------------------------------

G:ORACLEPRODUCT10.2.0ADMINORA10GUDUMPora10g_ora_3528.trc

查看ora10g_ora_3528.trc,下面是其中的部分信息:

Corrupt block relative dba: 0x01c00014 (file 7, block 20)

...

Corrupt block relative dba: 0x01c00013 (file 7, block 19)

...

跟踪文件中提示了数据文件7块19、20出现了坏块,下面使用DBV工具进行检测:

使用DBV工具时,两个参数是必须的,一个是FILE,一个是BLOCKSIZE:

G:oracleproduct10.2.0oradataora10g>dbv file=test01.dbf blocksize=8192

DBVERIFY - 开始验证: FILE = test01.dbf

页 19 标记为损坏

Corrupt block relative dba: 0x01c00013 (file 7, block 19)

...

页 20 标记为损坏

Corrupt block relative dba: 0x01c00014 (file 7, block 20)

...

页 23 标记为损坏

Corrupt block relative dba: 0x01c00017 (file 7, block 23)

...

页 31 标记为损坏

Corrupt block relative dba: 0x01c0001f (file 7, block 31)

...

DBVERIFY - 验证完成

检查的页总数: 128

处理的页总数 (数据): 106

失败的页总数 (数据): 0

处理的页总数 (索引): 0

失败的页总数 (索引): 0

处理的页总数 (其它): 18

处理的总页数 (段)  : 0

失败的总页数 (段)  : 0

空的页总数: 0

标记为损坏的总页数: 4

流入的页总数: 0

最高块 SCN            : 1286361 (0.1286361)

我们可以见到,使用DBV工具检测出了该对象存在了4个坏块,而上面我们使用analyze命令时只检测出部分的坏块。

3、使用dbms_repair包进行坏块处理

1)首先建立repair_table,用于存放dbms_repair.check_object检测出来的坏块信息

SQL> declare

2  begin

3  dbms_repair.admin_tables

4  (table_name => 'REPAIR_TABLE',--表名

5  table_type => dbms_repair.repair_table,

6  action => dbms_repair.create_action,

7  tablespace => 'USERS');--用于指定该表存放的表空间

8  end;

9  /

PL/SQL 过程已成功完成。

SQL> col owner format a10

SQL> col object_name format a20

SQL> col object_type format a20

SQL> select owner, object_name, object_type

2  from dba_objects

3  where object_name like '%REPAIR_TABLE';

OWNER      OBJECT_NAME          OBJECT_TYPE

---------- -------------------- --------------------

SYS        REPAIR_TABLE         TABLE

SYS        DBA_REPAIR_TABLE     VIEW

Oracle自动创建了一个DBA_REPAIR_TABLE视图。

2)使用dbms_repair.check_object进行坏块检测

SQL> set serveroutput on size 100000;

SQL> declare

2  rpr_count int;

3  begin

4  rpr_count := 0;

5  dbms_repair.check_object(

6  schema_name => 'SYS',--指定对象模式,也就是对象的所有者

7  object_name => 'TEST',--指定对象名,也就是表名

8  repair_table_name => 'REPAIR_TABLE',

9  corrupt_count => rpr_count);

10  dbms_output.put_line('repair block count: '

11  ||to_char(rpr_count));

12  end;

13  /

repair block count: 4

PL/SQL 过程已成功完成。

SQL> select object_name, block_id, corrupt_type, marked_corrupt,

2  corrupt_description, repair_description

3  from repair_table;

OBJECT_NAME            BLOCK_ID CORRUPT_TYPE MARKED_COR

-------------------- ---------- ------------ ----------

CORRUPT_DESCRIPTION

-------------------------------------------------------------------------------

REPAIR_DESCRIPTION

-------------------------------------------------------------------------------

TEST                         19         6148 TRUE

mark block software corrupt

TEST                         20         6148 TRUE

mark block software corrupt

TEST                         23         6148 TRUE

mark block software corrupt

TEST                         31         6148 TRUE

mark block software corrupt

通过运行dbms_repair.check_object,将坏块信息存放到了repair_table表中,其中有个字段marked_corrupt,用于标识该块是否被标识为坏块,当被标识为true时,即该块被标识为坏块。其中这一步跟oracle文档中的描述有点进入,根据oracle文档,当执行完dbms_repair.check_object时,并不会进行坏块标识,也就是marked_corrupt列的值应该为false,而只有当执行dbms_repair.fix_corrupt_blocks过程后才会进行坏块标识。

3)使用dbms_repair.fix_corrupt_blocks进行坏块标识

SQL> declare

2  fix_block_count int;

3  begin

4  fix_block_count := 0;

5  dbms_repair.fix_corrupt_blocks (

6  schema_name => 'SYS',

7  object_name => 'TEST',

8  object_type => dbms_repair.table_object,

9  repair_table_name => 'REPAIR_TABLE',

10  fix_count => fix_block_count);

11  dbms_output.put_line('fix blocks count: ' ||

12  to_char(fix_block_count));

13  end;

14  /

fix blocks count: 0

PL/SQL 过程已成功完成。

我们可以见到到fix blocks count=0,即在上一步进行check_object时已经进行了坏块标识了,这一步其实可以省略。(不过没有测试过!)

SQL> select count(*) from test;

select count(*) from test

*

第 1 行出现错误:

ORA-01578: ORACLE 数据块损坏 (文件号 7, 块号 19)

ORA-01110: 数据文件 7: 'G:ORACLEPRODUCT10.2.0ORADATAORA10GTEST01.DBF'

此时进行查询仍然报错,因为我们只是将坏块进行了标识,当进行全表扫描的时候,仍然会查询到坏块而报错。

4)使用dbms_repair.dump_orphan_keys过程来保存坏块的索引键值,然后再执行skip_corrupt_blocks过程之后,我们才能重建索引,不然重建索引时新的索引仍然会引用坏块。首先要建立ORPHAN_KEY_TABLE,此表就是用来存放坏块的索引键值。

SQL> declare

2  begin

3  dbms_repair.admin_tables

4  (table_name => 'ORPHAN_KEY_TABLE',

5  table_type => dbms_repair.orphan_table,

6  action => dbms_repair.create_action,

7  tablespace => 'USERS');

8  end;

9  /

PL/SQL 过程已成功完成。

然后执行过程dbms_repair.dump_orphan_keys将坏块键值存放到上面所创建的表中:

SQL> declare

2  orph_count int;

3  begin

4  orph_count:= 0;

5  dbms_repair.dump_orphan_keys (

6  schema_name => 'SYS',

7  object_name => 'ID_INX',--索引的名字

8  object_type => dbms_repair.index_object,

9  repair_table_name => 'REPAIR_TABLE',--从这个表中获得坏块的信息

10  orphan_table_name => 'ORPHAN_KEY_TABLE',

11  key_count => orph_count);

12  dbms_output.put_line('orphan-index entries: ' || to_char(orph_count));

13  end;

14  /

orphan-index entries: 491

PL/SQL 过程已成功完成。

SQL> declare

2  orph_count int;

3  begin

4  orph_count:= 0;

5  dbms_repair.dump_orphan_keys (

6  schema_name => 'SYS',

7  object_name => 'NAME_INX',

8  object_type => dbms_repair.index_object,

9  repair_table_name => 'REPAIR_TABLE',

10  orphan_table_name => 'ORPHAN_KEY_TABLE',

11  key_count => orph_count);

12  dbms_output.put_line('orphan-index entries: ' || to_char(orph_count));

13  end;

14  /

orphan-index entries: 491

PL/SQL 过程已成功完成。

对每个索引都要进行dump_orphan_keys。

SQL> select index_name, count(*) from orphan_key_table

2  group by index_name;

INDEX_NAME                       COUNT(*)

------------------------------ ----------

ID_INX                                491

NAME_INX                              491

5)使用skip_corrupt_blocks,使查询或者DML时跳过坏块

SQL> declare

2  begin

3  dbms_repair.skip_corrupt_blocks (

4  schema_name => 'SYS',

5  object_name => 'TEST',

6  object_type => dbms_repair.table_object,

7  flags => dbms_repair.skip_flag);

8  end;

9  /

PL/SQL 过程已成功完成。

SQL> select table_name, skip_corrupt from dba_tables

2  where table_name = 'TEST';

TABLE_NAME                     SKIP_COR

------------------------------ --------

TEST                           ENABLED

6)使用dbms_repair.rebuild_freelists重建freelists,使得该块不再被放到freelists,当中,也就是该块将不会再被使用。

SQL> declare

2  begin

3  dbms_repair.rebuild_freelists (

4  schema_name => 'SYS',

5  object_name => 'TEST',

6  object_type => dbms_repair.table_object);

7  end;

8  /

declare

*

第 1 行出现错误:

ORA-10614: Operation not allowed on this segment

ORA-06512: 在 "SYS.DBMS_REPAIR", line 400

ORA-06512: 在 line 3

不过我们可以看到,对于SYS用户下面的对象好像不能进行此操作。

4、重建索引

SQL> select count(id) from test;

COUNT(ID)

----------

19998

SQL> select count(name) from test;

COUNT(NAME)

-----------

19998

SQL> select count(*) from test;

COUNT(*)

----------

19507

我们可以看到上面的三个查询,对于第1和第2个使用索引进行查询和不使用索引进行查询的结果是不一样的。下面我们使用rebuild试试。

SQL> alter index id_inx rebuild;

索引已更改。

SQL> alter index name_inx rebuild;

索引已更改。

SQL> select count(id) from test;

COUNT(ID)

----------

19998

SQL> select count(name) from test;

COUNT(NAME)

-----------

19998

SQL> select count(*) from test;

COUNT(*)

----------

19507

可以是不能通过rebuild来重建索引的。只能通过DROP然后再CREATE。

SQL> drop index id_inx;

索引已删除。

SQL> drop index name_inx;

索引已删除。

SQL> create index id_inx on test(id);

索引已创建。

SQL> create index name_inx on test(name);

索引已创建。

SQL> select count(id) from test;

COUNT(ID)

----------

19507

SQL> select count(name) from test;

COUNT(NAME)

-----------

19507

SQL> select count(*) from test;

COUNT(*)

----------

19507

到此该表已经可以正常使用了,但同时也丢失了一些数据,所以在使用dbms_repair进行恢复的时候要充分考虑到数据的重要性和恢复的后果。同时也应该考虑是否有其它别的恢复方法,不然贸贸然的行事最后可能得不偿失。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/27573546/viewspace-759045/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/27573546/viewspace-759045/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值