暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

数据库文件损坏与坏块处理

suger 2023-05-27
1398


在数据库日常使用中,我们经常会遇到各种各样的坏块。在不同文件中或不同对象中的损坏或坏块有着不同的处理方式。

 

1.控制文件损坏处理:

控制文件遇到坏块时,基本现象就是控制文件的损坏,数据库无法启动到MOUNT,当然一般数据库都有多个控制文件组成。

如果遇到其中的一个或者几个控制文件损坏(不是全部控制文件损坏),那么我们可以通过修改pfile中的control file初始化参数去除损坏的控制文件,或者复制未损坏的控制文件来覆盖损坏的控制文件,来达到修复控制文件的目的。

如果遇到所有的控制文件损坏(没有做任何备份的情况下),那么就要我们手工来创建控制文件。

手工创建控制文件脚本列子如下(需要数据库在nomount下):

CREATE CONTROLFILE REUSE DATABASE "orcl" RESETLOGS NOARCHIVELOG

  MAXLOGFILES 16

  MAXLOGMEMBERS 3

  MAXDATAFILES 100

  MAXINSTANCES 8

  MAXLOGHISTORY 292

LOGFILE

  GROUP 1 '/oradata/orcl/redo01.log' SIZE 256M,

  GROUP 2 '/oradata/orcl/redo02.log' SIZE 256M,

  GROUP 3 '/oradata/orcl/redo03.log' SIZE 256M

DATAFILE

  '/oradata/orcl/SUPHISV3.dbf',

  '/oradata/orcl/SUPHISV301.dbf',

  '/oradata/orcl/SUPHISV302.dbf',

  '/oradata/orcl/SUPHISV303.dbf',

  '/oradata/orcl/SUPHISV304.dbf',

  '/oradata/orcl/SUPHISV305.dbf',

  '/oradata/orcl/SUPHISV3CJ.dbf',

  '/oradata/orcl/SUPHISV3CJ01.dbf',

  '/oradata/orcl/SUPHISV3CJ02.dbf',

  '/oradata/orcl/SUPHISV3CJ03.dbf',

  '/oradata/orcl/SUPNCIS.dbf',

  '/oradata/orcl/SUPNCIS2011.dbf',

  '/oradata/orcl/supncis01.dbf',

  '/oradata/orcl/supncis02.dbf',

  '/oradata/orcl/supncis03.dbf',

  '/oradata/orcl/supncis04.dbf',

  '/oradata/orcl/supncis05.dbf',

  '/oradata/orcl/supncis06.dbf',

  '/oradata/orcl/supncis07.dbf',

  '/oradata/orcl/supncis08.dbf',

  '/oradata/orcl/sysaux01.dbf',

  '/oradata/orcl/system01.dbf',

  '/oradata/orcl/undotbs01.dbf',

  '/oradata/orcl/users01.dbf'

CHARACTER SET ZHS16GBK;

注意上面脚本中标红的位置需要重点关注来进行修改。

orcl为数据库的SID

NORESETLOGS/RESETLOGS为是否要重置redo log文件

NOARCHIVELOG/ARCHIVELOG为数据库是否在归档模式

CHARACTER SET ZHS16GBK为数据库的字符集

 

关于是否要重置redo需要根据具体情况进行判断:

 

1.1对于在非归档模式下的数据库:

1) 当redo log文件为未损坏时,使用noresetlogs noarchivelog

此时,当完成控制文件的创建后,直接使用

alter database mount;

alter database open;

可以直接打开数据库。

2) 当redo log文件也同样损坏,使用resetlogs noarchivelog

alter database mount; 

alter system set "_allow_resetlogs_corruption"=true scope=spfile;   --这个参数是关键,可以允许Oracle重置REDO日志

recover database until cancel;  --使用CANCEL退出,运行后才可以使用resetlogs去open数据库

alter database open resetlogs;

 

 

 

 

1.2对于在归档模式下的数据库

1) 所有的online logs好的情况下,使用noresetlogs archvelog

alter database mount;

alter system switch log all;

alter database open;

2) 如果online logs损坏,使用resetlogs archivelog

对于至少有一个有效归档存在的环境(RAC必须每个节点都有至少一个归档)

recover database using backup controlfile until cancle;  --根据提示输入所需的归档文件的全路径

alter database open resetlogs;

 

对于没有归档存在的环境下

alter database mount; 

alter system set "_allow_resetlogs_corruption"=true scope=spfile;   --这个参数是关键,可以允许Oracle重置REDO日志

recover database until cancel;  --使用CANCEL退出,运行后才可以使用resetlogs去open数据库

alter database open resetlogs;

 

在上述各个情况下做完打开数据操作后,不要忘记添加temp表空间和做一次数据库全备。

当然可能还会遇到一些其他的报错信息,那么久需要对具体问题具体分析了。

 


 

2.Redo文件损坏处理:

使用命令查看损坏的redo log是不是当前的redo log,使用如下命令:

select group#,sequence#,archived,status from v$log;

 

2.1非current redo损坏

可进行删除,和重新添加的操作(注意至少有2组redo log文件),如:

ALTER DATABASE DROP LOGFILE GROUP 3;

Alter database add logfile thread 1 group 3 (‘/oradata/orcl/redo03.log’) size 256M;

 

2.2current redo损坏

1)  如果有归档和备份,可以用不完全恢复

startup mount;

recover database until cancel;  --先选择auto,尽量恢复可以利用的归档日志,然后重新执行:

recover database until cancel; --这次输入cancel,完成不完全恢复,

用resetlogs打开数据:

alter database open resetlogs; --打开数据库

 

2) 强制恢复,这种方法可能会导致数据不一致

startup mount;

alter system set "_allow_resetlogs_corruption"=true scope=spfile;

recover database until cancel;     --使用命令cancel

alter database open resetlogs;

一般强制恢复恢复后会有undo segment的问题。

一般操作为重建undo表空间,该步骤可在undo损坏中看到。

 

 

 


3.Undo文件损坏处理:

Oracle 的undo 有两种管理方式,通过参数undo_management来设置auto 和 manual。

 

1)  当undo_management被设置成MENUAL时使用系统回滚段, 即将undo records 记录到SYSTEM 表空间下的SYSTEM段。

 

SQL> select segment_name,tablespace_name,bytes,next_extent  from dba_segments where segment_type='ROLLBACK';

 

SEGMENT_NA TABLESPACE_NAME       BYTES NEXT_EXTENT

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

SYSTEM     SYSTEM                 393216     1048576

 

       通过上面的这条语句,我们查到了这个用于rollback 的system segment 存在与system 表空间。 默认情况下,只有一个segment,并且它还比较小,所以,如果使用system段来存储undo records。肯定会影响数据库的性能。 所以Oracle 是建议使用Undo tablespace 来管理undo records。

 

2)  当undo_management设置成AUTO时使用UNDO tablespace来管理回滚段。 这个时候,我们将有多个undo segment,并且这些segment 是存放在UNDO 表空间里的。 这样对DB的性能就会提高。

 

SQL> select segment_name,tablespace_name,bytes,next_extent  from dba_segments where segment_type='TYPE2 UNDO';

 

SEGMENT_NAME    TABLESPACE_NAME    BYTES NEXT_EXTENT

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

_SYSSMU1$            UNDOTBS1                1179648       65536

_SYSSMU2$            UNDOTBS1                1179648       65536

_SYSSMU3$            UNDOTBS1                2228224       65536

_SYSSMU4$            UNDOTBS1                1179648       65536

_SYSSMU5$            UNDOTBS1                 262144       65536

_SYSSMU6$            UNDOTBS1                1179648       65536

_SYSSMU7$            UNDOTBS1                1179648       65536

_SYSSMU8$            UNDOTBS1                1179648       65536

_SYSSMU9$            UNDOTBS1                1179648       65536

_SYSSMU10$           UNDOTBS1                1179648       65536

通过以上SQL的查询结果,我们可以看出,有10个undo segment来存放undo records。

 

       以上我们是通过dba_segment 表查看的结果。 也可以通过v$rollstat和v$rollname 两个视图来查看信息。 这2个视图会显示所有rollback 段的信息。 包括system段和undo段。

 

SQL> col name format a15

SQL> select s.usn,n.name,s.extents,s.hwmsize,s.status from v$rollstat s, v$rollname n where s.usn=n.usn;

 

       USN NAME               EXTENTS    HWMSIZE STATUS

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

         0 SYSTEM                   6     385024 ONLINE

         1 _SYSSMU1$                3    7659520 ONLINE

         2 _SYSSMU2$                3    9691136 ONLINE

         3 _SYSSMU3$                4    7462912 ONLINE

         4 _SYSSMU4$                3   76668928 ONLINE

         5 _SYSSMU5$                4    8511488 ONLINE

         6 _SYSSMU6$                3    7462912 ONLINE

         7 _SYSSMU7$                3   33480704 ONLINE

         8 _SYSSMU8$                3    8577024 ONLINE

         9 _SYSSMU9$                3    7462912 ONLINE

        10 _SYSSMU10$               3   13754368 ONLINE

 

11 rows selected.

 

3) UNDO 损坏的情况

 

出现这种情况,大多数是因为异常宕机,在启动的时候报的错误。DB 不能启动。

       比如:ORA-00600: internal error code, arguments: [4194],  

 

       对于Undo 损坏的情况,能用备份恢复最好,如果不能,就只能通过一些特殊的方法来恢复。

 

方法一:使用system segment

步骤如下:

 

(1)用spfile 创建pfile,然后修改参数:

#*.undo_tablespace='UNDOTBS1'

#*.undo_management='AUTO'

#*.undo_tablespace

#*.undo_retention

undo_management='MANUAL'

rollback_segments='SYSTEM'

 

(2)用修改之后的pfile,重启DB

SQL> STARTUP MOUNT pfile='/oracle/product/10.2.0/dbs/initorcl.ora' ;

 

(3)删除原来的表空间,创建新的UNDO 表空间

SQL> drop tablespace undotbs;

SQL> create undo tablespace undotbs1 datafile '/u01/oradata/undotbs1.dbf' size 10M;

 

(4)关闭数据库,修改pfile参数,然后用新的pfile创建spfile,在正常启动数据库。

*.undo_tablespace='UNDOTBS1'

*.undo_management='AUTO'

#undo_management='MANUAL'

#rollback_segments='SYSTEM'

 

 

 方法二:跳过损坏的segment

       在方法一里面,使用了system segment。undo segment 一般有多个,我们可以通过alert log 来查看正在使用的是哪些segment,这些段有可能损坏了。那么只需要把这些损坏的segment 跳过,先正常启动DB,在创建新的UNDO 表空间,在切换一下。

 

(1)修改pfile,添加参数:

*._corrupted_rollback_segments='_SYSSMU11$','_SYSSMU12$','_SYSSMU13$'

 

这些字段的值,我们通过alert log 查看。 也可以通过如下命令查看:

#strings system01.dbf | grep _SYSSMU | cut -d $ -f 1 | sort -u

 

(2)用修改之后的pfile启动DB

       因为跳过了哪些损坏的segment,所以DB 可以正常启动。

 

(3)创建新的UNDO 表空间,并切换过来

 

SQL> create undo tablespace undotbs1 datafile '/u01/oradata/undotbs1.dbf' size 10M;

SQL> alter system set undo_tablespace=undotbs1;

SQL> drop tablespace undotbs;

 

(4)修改pfile,创建spfile,并正常启动

删除:

*._corrupted_rollback_segments='_SYSSMU11$','_SYSSMU12$','_SYSSMU13$'

 

SQL> select segment_name,status from dba_rollback_segs  ;  --查看rollback_segment

 

此时回滚段状态为offline,现在都可以删除了:

 

SQL> drop rollback segment "_SYSSMU11$" ;

SQL> drop rollback segment "_SYSSMU12$" ;

SQL> drop rollback segment "_SYSSMU13$" ;

 

 

 

 

 

 

 


4.DATAFILE坏块处理

4.1什么是数据库的坏块

数据库的数据块有固定的格式和结构,分三层:cache layer,transaction layer,data layer。对数据块进行读取写入操作的时候,数据库会对要读写的数据块做一致性的检查,其中包括:数据块的类型、数据块的地址信息、数据块的SCN号以及数据块的头部和尾部。如果发现其中有不一致的信息,那数据库就会标记这个数据块为坏块了。数据库的坏块分为两种,逻辑坏块和物理坏块。

 

4.2坏块对数据库产生的影响

 

如果数据库出现坏块,数据库的告警日志文件里面会存在有如下的一些报错信息:Ora-1578以及Ora-600 and trace file in bdump directory,其中Ora-600错误的第一个参数值的范围是[2000]-[8000],不同的值代表着数据块的不同的层出现问题,具体的如下表所示:

Range                   block layer

Cache layer                  2000 – 4000

Transaction layer                  4000 – 6000

Data layer                  6000 - 8000

坏块产生影响的对象可能是数据字典表、回滚段表、临时段、用户数据表和索引等。不同的对象产生坏块后的处理方法不尽相同。

 

4.3坏块产生的原因

Oracle调用标准C的系统函数,对数据块进行读写操作,因此,坏块是有可能由以下几种原因产生:

硬件的I/O错误

操作系统的I/O错误或缓冲问题

内存或paging问题

磁盘修复工具

一个数据文件的一部分正在被覆盖

Oracle试图访问一个未被格式化的系统块失败

数据文件部分溢出

Oracle或者操作系统的bug

 

4.4坏块的处理方法

1) 先收集相应的关于坏快的信息,从AlertSID.log文件或者从trace文件中查找,找到例如以下的一些信息:

  Ora-1578  file#  (RFN)  block#

Ora-1110  file#  (AFN)  block#

    Ora-600   file#  (AFN)  block#

其中RFN表示的是relative_fno

AFN表示的是file_id

        Select file_name,tablespace_name,file_id “AFN”,relative_fno “RFN”

       From dba_data_files;

        Select file_name,tablespace_name,file_id, relative_fno“RFN”

        From dba_temp_files;

2)  确定存在坏块的对象是什么:

    SELECT tablespace_name, segment_type, owner, segment_name, partition_name  FROM dba_extents WHERE file_id = <AFN> and <BL> between block_id AND block_id + blocks – 1;

    通过上面这个查询语句就可以查出当前存在坏块的对象是什么,是什么类型的对象。需要注意的是如果是temp文件中出现坏块,是没有记录返回的。

3)  根据2)中查询出来的对象类型,确定相应的处理方法

出现坏块的常见对象有:

sys用户下的对象

回滚段

临时段

索引或者分区索引

常用的处理方法有:

恢复数据文件

只恢复坏的block(9i以上版本可用)

通过ROWID RANGE SCAN 保存数据

使用DBMS_REPAIR

使用EVENT

4)  具体处理方法的介绍

 

Ø         恢复数据文件方法:

如果数据库是归档方式下,并且有完整的物理备份,就可以使用此方法来恢复。

步骤如下:

(1)       先offline受影响的数据文件,执行以下的语句:

    ALTER DATABASE DATAFILE 'name_file' OFFLINE;

(2)       保留有坏块的数据文件,然后拷贝备份的数据文件。如果恢复的数据文件要求路径不同,执行以下的语句:

    ALTER DATABASE RENAME FILE 'old_name' TO 'new_name';

(3)       恢复数据文件,执行以下语句:

    RECOVER DATAFILE 'name_of_file';

(4)       Online恢复后的数据文件,执行以下的语句:

ALTER DATABASE DATAFILE 'name_of_file' ONLINE;

 

Ø       只恢复坏的block(9i以上版本可用)

   使用这种方法要求数据库版本是9.2.0以上,要求配置了Rman的catalog数据库,数据库为归档方式,并且有完整的物理备份。

   步骤如下:

   使用RMAN的BLOCKRECOVER命令 :

   Rman>run{blockrecover datafile 5 block 11,16;}

   也可以强制使用某个SCN号之前的备份,恢复数据块。

   Rman>run{blockrecover datafile 5 block 11,16 restore until sequence 8505;}

 

Ø       通过ROWID RANGE SCAN 保存数据

1)    先取得坏块中ROW ID的最小值,执行以下的语句:

   SELECT dbms_rowid.rowid_create(1,<OBJ_ID>,<RFN>,<BL>,0) from DUAL;

2)取得坏块中的ROW ID的最大值,执行以下的语句:

   SELECT dbms_rowid.rowid_create(1,<OBJ_ID>,<RFN>,<BL>+1,0) from DUAL;

3)建议一个临时表存储那些没有坏块的数据,执行以下的语句:

   CREATE TABLE salvage_table AS SELECT  *   FROM  corrupt_tab Where 1=2;

4)保存那些不存在坏块的数据到临时表中,执行以下的语句:

   INSERT INTO salvage_table SELECT /*+ ROWID(A) */ * FROM <owner.tablename> A WHERE rowid < '<low_rid>';

INSERT INTO salvage_table SELECT /*+ ROWID(A) */ * FROM <owner.tablename> A  WHERE rowid >= '<hi_rid>';

5) 根据临时表中的数据重建表,重建表上的索引,限制。

 

Ø       使用10231诊断事件,在做全表扫描的时候跳过坏块

可以在session级别设定:

ALTER SESSION SET EVENTS '10231 TRACE NAME CONTEXT FOREVER, LEVEL 10';

也可以在数据库级别上设定,在初始化参数中加入:event="10231 trace name context forever, level 10" ,然后重启数据库。

然后从存在坏块的表中取出不存在坏块的数据,执行以下的语句:

CREATE TABLE salvage_emp AS SELECT * FROM corrupt_table;

最后rename生成的corrupt_table为原来表的名字,并重建表上的索引和限制。

 

Finished recover at 2013-03-29 12:35:09================================================第二种恢复方法就是开启 10231事件,全表扫描的时候会跳过坏块,用EXP/EXPDP导出相应的表,再把原来的表删除,把数据导入进去:SQL> ALTER SYSTEM SET EVENTS='10231 trace name context forever,level 10' ;System altered.然后导出表中的数据(不过这种恢复有的时候会丢数据,因为坏块中的数据已经跳过了)exp qjh/qjh tables=test file=test.dmp log=exp_test.log删除表:drop table test purge;导入数据:imp qjh/qjh tables=test file=test.dmp log=imp_test.log关闭10231事件:SQL> ALTER SYSTEM SET EVENTS='10231 trace name context off' ;       

 

Ø       使用dbms_repair包进行恢复

   使用dbms_repair标记有坏块的表,在做全表扫描的时候跳过坏块,执行以下的语句:

Execute DBMS_REPAIR.SKIP_CORRUPT_BLOCKS('<schema>','<tablename>');

然后使用导入导出工具或者createtable as select的方法取出没有坏块数据,然后重建表,表上的索引和限制。

 

4.5坏块的预先发现的方法

1) 如果要检测数据库中所有的表,可以利用exp工具导出整个数据库可以检测坏块。不过这个工具有一些缺陷,对以下情况的坏块是检测不出来的:

 HWM以上的坏块是不会发现的

Ø  索引中存在的坏块是不会发现的

Ø  数据字典中的坏块是不会发现的

 

2) 如果只是对数据库中比较重要的表进行坏块检查,可以使用ANALYZE TABLE tablename VALIDATE STRUCTURE CASCADE 的方法来检测坏块,它执行坏块的检查,但是不会标记坏块为corrupt,检测的结果保存在USER_DUMP_DEST目录下的用户trace文件中。

 

3)  使用Oracle的专门工具dbv来检查坏块,具体的语法如下:

关键字     说明                    (默认)

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

FILE        要验证的文件                 (无)

START       起始块                    (文件的第一个块)

END         结束块                      (文件的最后一个块)

BLOCKSIZE   逻辑块大小             (2048)

LOGFILE     输出日志                     (无)

FEEDBACK    显示进度               (0)

PARFILE     参数文件                 (无)

USERID      用户名/口令              (无)

SEGMENT_ID  段 ID (tsn.relfile.block) (无)

 

例如:

Dbv file=system01.dbf blocksize=8192

DBVERIFY: Release 9.2.0.5.0 - Production on 星期六 11月 27 15:29:13 2004

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

DBVERIFY - 验证正在开始 : FILE = system01.dbf

DBVERIFY - 验证完成

检查的页总数         :32000

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

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

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

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

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

处理的总页数 (段)  : 0

失败的总页数 (段)  : 0

空的页总数            :15186

标记为损坏的总页数:0

汇入的页总数           :0

    注:因为dbv要求file后面跟的必须是一个文件扩展名,所以如果用裸设备存储的,就必须使用ln链接裸设备到一个文件,然后再用dbv对这个链接文件进行检查。

 

 

5.修复示例

 

SQL> create tablespace block datafile 'D:\oracle\oradata\oracle9i\block.dbf' size 5M;

Tablespace created

SQL> connect dlinger/dlinger

Connected to Oracle9i Enterprise Edition Release 9.2.0.1.0

Connected as dlinger

QL> create table test tablespace block as select * from all_tables;

Table created

SQL> insert into test select * from test;

806 rows inserted

SQL> insert into test select * from test;

1612 rows inserted

SQL> insert into test select * from test;

3224 rows inserted

SQL> insert into test select * from test;

6448 rows inserted

SQL> insert into test select * from test;

insert into test select * from test

ORA-01653: 表DLINGER.TEST无法通过128(在表空间BLOCK中)扩展

SQL> commit;

Commit complete

SQL> select count(*) from test;

COUNT(*)

----------

12896

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

数据库装载完毕。

数据库已经打开。

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

select count(*) from dlinger.test

*

ERROR 位于第 1 行:

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

ORA-01110: 数据文件 14: 'D:\ORACLE\ORADATA\ORACLE9I\BLOCK.DBF'

用dbv检查:

C:\Documents and Settings\duanl>dbv file='D:\oracle\oradata\oracle9i\block.dbf'

blocksize=8192

DBVERIFY: Release 9.2.0.1.0 - Production on 星期二 8月 24 19:58:15 2004

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

DBVERIFY - 验证正在开始 : FILE = D:\oracle\oradata\oracle9i\block.dbf

标记为损坏的页160

***

Corrupt block relative dba: 0x038000a0 (file 14, block 160)

Bad check value found during dbv:

Data in bad block -

type: 6 format: 2 rdba: 0x038000a0

last change scn: 0x0000.0035f5c2 seq: 0x1 flg: 0x06

consistency value in tail: 0xf5c20601

check value in block header: 0x3681, computed block checksum: 0x5bb

spare1: 0x0, spare2: 0x0, spare3: 0x0

***

DBVERIFY - 验证完成

检查的页总数 :640

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

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

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

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

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

处理的总页数 (段) : 0

失败的总页数 (段) : 0

空的页总数 :120

标记为损坏的总页数:1

汇入的页总数 :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.检查坏块:dbms_repair.check_object 

SQL> declare

2 cc number;

3 begin

4 dbms_repair.check_object(schema_name => 'DLINGER',object_name => 'TEST',cor

rupt_count => cc);

5 dbms_output.put_line(a => to_char(cc));

6 end;

7 /

1

PL/SQL 过程已成功完成。

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

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

SQL> SELECT object_name, relative_file_id, block_id,marked_corrupt, corrupt_description, repair_description,

2 CHECK_TIMESTAMP from repair_table;

OBJECT_NAME RELATIVE_FILE_ID BLOCK_ID MARKED_CORRUPT CORRUPT_DESCRIPTION REPAIR_DESCRIPTION CHECK_TIMESTAMP

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

TEST 14 160 TRUE mark block software corrupt 2004-8-24 21:46

在这个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 => 'DLINGER',object_name => 'TEST',fix_count => cc);

dbms_output.put_line(a => to_char(cc));

end;

4.跳过坏块: 

我们前面虽然定位了坏块,但是,如果我们访问table:

SQL> select count(*) from dlinger.dbblock;

select count(*) from dlinger.dbblock

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

ORA-01110: 数据文件 14: 'D:\ORACLE\ORADATA\ORACLE9I\BLOCK.DBF'

还是会得到错误信息。

这里需要用skip_corrupt_blocks来跳过坏块: 

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

PL/SQL procedure successfully completed

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

COUNT(*)

----------

12850

丢失了12896-12850=46行数据。

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

declare

cc number;

begin

dbms_repair.dump_orphan_keys(schema_name => 'DLINGER',object_name => 'I_TEST',object_type => 2,

repair_table_name => 'REPAIR_TABLE',orphan_table_name => 'ORPHAN_TABLE',key_count => CC);

end;

/

SQL> SELECT * FROM ORPHAN_TABLE;

SCHEMA_NAME INDEX_NAME IPART_NAME INDEX_ID TABLE_NAME PART_NAME TABLE_ID KEYROWID KEY DUMP_TIMESTAMP

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

DLINGER I_TEST 30258 TEST 30257 AAAHYxAOwAAAIADA0A *BAAAAAAMTE9HTU5SQ19HU0lJ/g 2004-8-25 22:1

DLINGER I_TEST 30258 TEST 30257 AAAHYxAOwAAAIADAsA *BAAAAAAMTE9HTU5SQ19HVExP/g 2004-8-25 22:1

..............................................

DLINGER I_TEST 30258 TEST 30257 AAAHYxAOwAAAIADB0A *BAAAAAAPTE9HTU5SX0xPQkZSQUck/g 2004-8-25 22:1

DLINGER I_TEST 30258 TEST 30257 AAAHYxAOwAAAIADBYA *BAAAAAAMTE9HTU5SX1RZUEUk/g 2004-8-25 22:1

DLINGER I_TEST 30258 TEST 30257 AAAHYxAOwAAAIADAQA *BAAAAAALTE9HTU5SX1VJRCT+ 2004-8-25 22:1

DLINGER I_TEST 30258 TEST 30257 AAAHYxAOwAAAIADAoA *BAAAAAAMTE9HTU5SX1VTRVIk/g 2004-8-25 22:1

46 rows selected

和上面我们看到的损失的数据行数吻合。

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

6.重建freelist:rebuild_freelists 

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

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论