block corruption

块折断(也称为块损坏)

块折断分为两种:硬折断和软折断。

硬折断:数据块的格式已经不是ORACLE数据块的格式了,如磁道损害,磁道被重新擦写等。

软折断:数据块的格式还是ORACLE的格式,但数据块内部出现了数据不一致的情况。也就是数据块内部无法经过正常的校验。这种情况常常是BUG引起的,或程序错误、异常导致数据块的数据不一致的情况。有些数据块可能在内存中就有问题,所以写到磁盘上的数据后就会有问题。

   

软折断的模拟

单独创立一个表空间:

SQL> create tablespace lxtbs01 datafile 'd:\u01\app\oracle\oradata\prod\lxtbs01.dbf' size 50m;

   

表空间已创建。

   

SQL>

在表空间上建立一个表:

SQL> create table tt tablespace lxtbs01 as select * from dba_objects;

   

表已创建。

   

SQL> insert into tt select * from tt;

   

已创建72462行。

   

SQL> commit;

   

提交完成。

   

SQL>

将表空间对应的数据文件用UE打开并修改

如何悠:将光标移动到要修改的字符上,先按r再按要替换成的字符就行了,注意数据格式为16进制,数字为0到9,字母为A到F

如果深入研究,则可以做到想让哪个块损坏就让哪个坏损坏

修改完成后保存并关闭后重新启动数据库,发现可以正常启来

SQL> shutdown immediate;

数据库已经关闭。

已经卸载数据库。

ORACLE 例程已经关闭。

SQL> startup

ORACLE 例程已经启动。

   

Total System Global Area 855982080 bytes

Fixed Size 2180544 bytes

Variable Size 503319104 bytes

Database Buffers 348127232 bytes

Redo Buffers 2355200 bytes

数据库装载完毕。

数据库已经打开。

SQL>

SQL> select file#,checkpoint_change# from v$datafile;

   

FILE# CHECKPOINT_CHANGE#

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

1 1090854

2 1090854

3 1090854

4 1090854

5 1090854

6 1090854

   

已选择6行。

   

SQL> select file#,checkpoint_change# from v$datafile_header;

   

FILE# CHECKPOINT_CHANGE#

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

1 1090854

2 1090854

3 1090854

4 1090854

5 1090854

6 1090854

   

已选择6行。

   

SQL>

能正常启动,是因为修改的不是数据文件的最前面的8个块(头8个块是打开数据库前要检查的,存放的是数据文件SCN等相关重要信息),数据文件满足打开数据库的一些条件。但查询数据文件里面涉及的表就会报错了,如下:

SQL> select count(*) from tt;

select count(*) from tt

*

第 1 行出现错误:

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

ORA-01110: 数据文件 6: 'D:\U01\APP\ORACLE\ORADATA\PROD\LXTBS01.DBF'

   

查询数据时检测到数据文件有坏块,直接抛出第一个坏块的信息,修复好第一个块后会抛出第二个坏块的信息

检测数据块是否完好,ORACLE提供了以下方法:

DBVERIFY其实就是DBV命令

   

当用命令检查的时候也会报错:

SQL> analyze table tt validate structure;

analyze table tt validate structure

*

第 1 行出现错误:

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

ORA-01110: 数据文件 6: 'D:\U01\APP\ORACLE\ORADATA\PROD\LXTBS01.DBF'

   

   

加上关键字cascade表示不仅检查表tt,还同时检查和tt表相关的其他所有对象

SQL> analyze table tt validate structure cascade;

analyze table tt validate structure cascade

*

第 1 行出现错误:

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

ORA-01110: 数据文件 6: 'D:\U01\APP\ORACLE\ORADATA\PROD\LXTBS01.DBF'

   

   

SQL>

如果是没有问题的表,则检查时就不会报错:

SQL> analyze table scott.emp validate structure cascade;

   

表已分析。

   

SQL>

操作系统提供了一个命令dbv来检查数据文件是否损坏

FILE指定要检测的文件

START 和 END 是当数据文件比较大的时候可以指定起始块和结束块

BLOCKSIZE指定数据文件块大小,默认是8192也就是8K,如果不是数据文件数据块不是默认8K则要指定这个参数

LOGFILE 将输出日志 保护到一个文件里面

FEEDBACK:显示进度条

PARFILE:检测的命令可以放到一个参数文件里面,可以直接调用参数文件来做检测,而不用每次都输入命令

USERID SEGMENT_ID HIGH_SCN 可以直接检查某用户的某个段

   

用dbv验证可以得出哪些数据块损坏:

这里的页也就是指数据块

如果数据文件不是标准块,要指定blocksize参数,否则会报错:

   

rdba:relative data block address

   

在备份前检测数据块有没有损坏:

RMAN> backup validate database;

   

启动 backup 于 17-1月 -13

使用目标数据库控制文件替代恢复目录

分配的通道: ORA_DISK_1

通道 ORA_DISK_1: SID=39 设备类型=DISK

分配的通道: ORA_DISK_2

通道 ORA_DISK_2: SID=32 设备类型=DISK

通道 ORA_DISK_1: 正在启动压缩的全部数据文件备份集

通道 ORA_DISK_1: 正在指定备份集内的数据文件

输入数据文件: 文件号=00001 名称=D:\U01\APP\ORACLE\ORADATA\PROD\SYSTEM01.DBF

输入数据文件: 文件号=00004 名称=D:\U01\APP\ORACLE\ORADATA\PROD\USERS01.DBF

输入数据文件: 文件号=00006 名称=D:\U01\APP\ORACLE\ORADATA\PROD\LXTBS01.DBF

通道 ORA_DISK_2: 正在启动压缩的全部数据文件备份集

通道 ORA_DISK_2: 正在指定备份集内的数据文件

输入数据文件: 文件号=00002 名称=D:\U01\APP\ORACLE\ORADATA\PROD\SYSAUX01.DBF

输入数据文件: 文件号=00005 名称=D:\U01\APP\ORACLE\ORADATA\PROD\EXAMPLE01.DBF

输入数据文件: 文件号=00003 名称=D:\U01\APP\ORACLE\ORADATA\PROD\UNDOTBS01.DBF

通道 ORA_DISK_1: 备份集已完成, 经过时间:00:00:15

数据文件列表

=================

文件状态 标记为损坏 空块 已检查的块 高 SCN

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

1 OK 0 13973 88326 1093073

文件名: D:\U01\APP\ORACLE\ORADATA\PROD\SYSTEM01.DBF

块类型 失败的块 已处理的块

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

数据 0 58640

索引 0 12174

其他 0 3533

   

文件状态 标记为损坏 空块 已检查的块 高 SCN

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

4 OK 0 255 640 978072

文件名: D:\U01\APP\ORACLE\ORADATA\PROD\USERS01.DBF

块类型 失败的块 已处理的块

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

数据 0 91

索引 0 39

其他 0 255

   

文件状态 标记为损坏 空块 已检查的块 高 SCN

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

6 FAILED 0 4145 6400 1091128

文件名: D:\U01\APP\ORACLE\ORADATA\PROD\LXTBS01.DBF

块类型 失败的块 已处理的块

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

数据 2 2086

索引 0 0

其他 0 169

   

验证找到一个或多个损坏的块

有关详细资料, 请参阅跟踪文件 d:\u01\app\oracle\diag\rdbms\prod\prod\trace\pro

通道 ORA_DISK_1: 正在启动压缩的全部数据文件备份集

通道 ORA_DISK_1: 正在指定备份集内的数据文件

备份集内包括当前控制文件

通道 ORA_DISK_2: 备份集已完成, 经过时间:00:00:15

数据文件列表

=================

文件状态 标记为损坏 空块 已检查的块 高 SCN

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

2 OK 0 19058 62785 1093071

文件名: D:\U01\APP\ORACLE\ORADATA\PROD\SYSAUX01.DBF

块类型 失败的块 已处理的块

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

数据 0 10266

索引 0 7049

其他 0 26347

   

文件状态 标记为损坏 空块 已检查的块 高 SCN

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

3 OK 0 500 10880 1093073

文件名: D:\U01\APP\ORACLE\ORADATA\PROD\UNDOTBS01.DBF

块类型 失败的块 已处理的块

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

数据 0 0

索引 0 0

其他 0 10380

   

文件状态 标记为损坏 空块 已检查的块 高 SCN

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

5 OK 0 1733 12804 1014837

文件名: D:\U01\APP\ORACLE\ORADATA\PROD\EXAMPLE01.DBF

块类型 失败的块 已处理的块

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

数据 0 4413

索引 0 1262

其他 0 5392

   

通道 ORA_DISK_2: 正在启动压缩的全部数据文件备份集

通道 ORA_DISK_2: 正在指定备份集内的数据文件

备份集内包括当前的 SPFILE

通道 ORA_DISK_1: 备份集已完成, 经过时间:00:00:00

控制文件和 SPFILE 的列表

===============================

文件类型 状态 失败的块 已检查的块

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

控制文件 OK 0 594

通道 ORA_DISK_2: 备份集已完成, 经过时间:00:00:00

控制文件和 SPFILE 的列表

===============================

文件类型 状态 失败的块 已检查的块

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

SPFILE OK 0 2

完成 backup 于 17-1月 -13

   

RMAN>

用RMAN的 backup validate database 命令检测完成后,如果有坏块,会将坏块写入到如下视图:

select * from v$database_block_corruption;

在警告日志里面也可以看到相关的块损坏:

   

ORACLE从9i开始支持用RMAN备份来修复数据块,最早没有提供这种功能,使用BBED来修复坏块。

BBED:block browse and edit.在这里不做论述。

利用RMAN备份恢复坏块:

再次检测发现只有一个错误了:

再来恢复一下:

恢复后再通过命令dbv来检测发现已经没有坏块了。

用analyze来分析也没有坏块了。

SQL> analyze table tt validate structure;

   

表已分析。

   

SQL>

对数据文件6再来进行一次备份前的校验

RMAN> backup validate datafile 6;

   

启动 backup 于 17-1月 -13

使用目标数据库控制文件替代恢复目录

分配的通道: ORA_DISK_1

通道 ORA_DISK_1: SID=40 设备类型=DISK

分配的通道: ORA_DISK_2

通道 ORA_DISK_2: SID=42 设备类型=DISK

通道 ORA_DISK_1: 正在启动压缩的全部数据文件备份集

通道 ORA_DISK_1: 正在指定备份集内的数据文件

输入数据文件: 文件号=00006 名称=D:\U01\APP\ORACLE\ORADATA\PROD\LXTBS01.DBF

通道 ORA_DISK_1: 备份集已完成, 经过时间:00:00:01

数据文件列表

=================

文件状态 标记为损坏 空块 已检查的块 高 SCN

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

6 OK 0 4145 6400 1091128

文件名: D:\U01\APP\ORACLE\ORADATA\PROD\LXTBS01.DBF

块类型 失败的块 已处理的块

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

数据 0 2086

索引 0 0

其他 0 169

   

完成 backup 于 17-1月 -13

   

RMAN>

   

块恢复后再用backup validate database 检测一下,才会更新下面数据字典,发现已无坏块:

SQL> select * from v$database_block_corruption;

   

未选定行

   

SQL>

备份前可以先对数据库、数据文件、表空间做一个检查

RMAN> backup validate database;

RMAN> backup validate datafile 6;

RMAN> backup validate tablespace users;

查看恢复时会转储哪些备份

RMAN> restore preview database;

利用包DBMS_REPAIR来检测块损坏:

如果数据文件损坏,且没有备份,则可以用包dbms_repair来标记坏块,访问时跳过坏块,而不是报错。

首先要建立一张表用来存放损坏块的信息,利用包DBMS_REPAIR来创建

BEGIN

DBMS_REPAIR.ADMIN_TABLES(

table_name => 'REPAIR_TABLE',

TABLE_TYPE => DBMS_REPAIR.REPAIR_TABLE,

ACTION => DBMS_REPAIR.CREATE_ACTION,

TABLESPACE => 'USERS'); // 也可以放到SYSTEM 表空间及其他表空间里

END;

创建成功后我们看到没有任务数据

   

SQL> SELECT * FROM REPAIR_TABLE;

   

no rows selected

   

SQL>

执行过程,统计坏块,这里只是统计并不会标记这些块是坏的。如果一个块被标记为坏块。则

set serveroutput on

declare num_corrupt int;

begin

num_corrupt :=0;

dbms_repair.check_object(

schema_name => 'SYS',

object_name => 'TT',

repair_table_name => 'REPAIR_TABLE',

corrupt_count => num_corrupt);

dbms_output.put_line(num_corrupt);

END;

/

dbms_output.put_line(num_corrupt); // 用来输出坏块数据量

查看表REPAIR_TABLE,里面有了数据

SQL> SELECT count(*) FROM REPAIR_TABLE;

   

COUNT(*)

----------

5

   

SQL>

SQL> select OBJECT_ID,BLOCK_ID,OBJECT_NAME,REPAIR_DESCRIPTION from REPAIR_TABLE;

   

OBJECT_ID BLOCK_ID OBJECT_NAME REPAIR_DESCRIPTION

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

74569 781 TT mark block software corrupt // 可以看到是软损坏

74569 961 TT mark block software corrupt

74569 1326 TT mark block software corrupt

74569 1723 TT mark block software corrupt

74569 2197 TT mark block software corrupt

   

SQL>

将数据文件的坏块做标记,在访问时可以忽略坏块,以至于不报错,在没有标记坏块之前查询表会报错:

SQL> select count(*) from tt;

select count(*) from tt

*

ERROR at line 1:

ORA-01578: ORACLE 数据块损坏 (文件号 6, 块号 781) ORA-01110:

数据文件 6: 'D:\U01\APP\ORACLE\ORADATA\PROD\LXTBS01.DBF'

   

   

SQL>

   

用包DBMS_REPAIRE来标记坏块

SQL> exec dbms_repair.skip_corrupt_blocks(schema_name=>'SYS',OBJECT_NAME=>'TT');

   

PL/SQL procedure successfully completed.

   

SQL>

   

跳过去以后再查看就没问题了:

SQL> select count(*) from tt;

   

COUNT(*)

----------

144572

   

SQL>

执行上面的存储过程表其实就是更新了系统表DBA_TABLES

SQL> select skip_corrupt from dba_tables where table_name='TT';

   

SKIP_COR

--------

ENABLED

   

SQL>

再将标记过的坏块取消其标记,也就是让DBA_TABLES的SKIP_CORRUPT为DISABLE

SQL> exec dbms_repair.skip_corrupt_blocks(schema_name=>'SYS',object_name=>'TT',flags=>dbms_repair.noskip_flag);

   

PL/SQL procedure successfully completed.

   

SQL>

flags有两个值可选择:noskip_flag和skip_flag 前者表示2,后者表示1

如果设置为不路过坏块,则又会报错:

SQL> select count(*) from tt;

select count(*) from tt

*

ERROR at line 1:

ORA-01578: ORACLE 数据块损坏 (文件号 6, 块号 781) ORA-01110:

数据文件 6: 'D:\U01\APP\ORACLE\ORADATA\PROD\LXTBS01.DBF'

   

SQL>

我们可以单独为某个段进行检测,如果某个段特别大,而且跨了好几十个数据文件,那么以数据文件为单位进行检测则非常慢;

   

SEGMENT_ID 的三项内容表示下面的三个字段

SQL> select tablespace_id,header_file,header_block from sys_dba_segs where segment_name='TT';

   

TABLESPACE_ID HEADER_FILE HEADER_BLOCK

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

7 6 130

   

SQL>

DB_BLOCK_CHECKING是一个参数

SQL> show parameter DB_BLOCK_CHECKING

   

NAME TYPE VALUE

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

db_block_checking string FALSE

SQL>

这个参数的作用就实时的验证数据块的完整性

后来因为这个参数的值太少就把FLASE改为了OFF

   

   

   

   

posted @ 2013-01-24 10:20  -Bill  阅读(515)  评论(0编辑  收藏  举报