分享

问题剖析:Oracle数据库坏块--物理坏块

 数据和云 2020-07-01


彭小波 

ACOUG核心成员,Oracle用户组年轻专家。擅长Oracle数据库架构规划、SQL,OWI方面的优化。曾服务于各大企业数据库的维护以及系统开发,目前从事百年人寿保险股份有限公司的数据库服务与运维工作。

编辑手记:感谢作者的文章和授权,今天我们来学习数据库中对物理坏块的分析及相关的处理!

数据库坏块(corruption) 的类型可以按照坏块所属对象的不同,分为用户数据坏块,数据字典坏块,undo 坏块,控制文件坏块,redo 坏块,lob坏块,index 坏块等;也可以按照坏块产生的原因,分为物理坏块( physical corruption )和逻辑坏块( logical corruption )。

本文主要讨论用户数据发生物理坏块( physical corruption )分析和解决方法。

常见的物理坏块(Physical Block Corruptions)有块头和块尾信息不一致( Fractured/Incomplete),checksum 值无效,数据块信息全部为0等情况,并且可能伴随错误 ORA-1578 和 ORA-1110。

为了及时发现物理坏块和准确定位坏块产生的原因,Oracle 建议设置初始化参数 DB_BLOCK_CHECKSUM=TYPICAL(默认值)。一般情况下,物理坏块是由于底层 OS/disk 系统错误/损坏,导致数据块被修改,数据块标志为坏块( corruption )。

Case分享

数据块的 Checksum 值无效是一种常见的物理坏块,当数据库初始化参数 DB_BLOCK_CHECKSUM=TYPICAL(默认值)时,DBWR 进程将数据块写入 disk 时会计算数据块的 Checksum,并且将 Checksum 值记录在数据块的位置 offset 16和17;当从 disk 读取该数据块时,oracle 重新计算数据块的 Checksum,并且与记录在数据块中的 Checksum 做异或运算(Xor),如果异或结果为非0,说明数据块被修改过,数据块为坏块( corruption )。


1. 当前数据库初始化参数配置 DB_BLOCK_CHECKSUM=TYPICAL,因此从 disk 读取数据块时校验 checksum:

SQL> show parameter DB_BLOCK_CHECKSUM

NAME                               TYPE       VALUE

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

db_block_checksum    string    TYPICAL

2. 查询表 dept 时发现有坏块,报错信息 ORA-1578 和 ORA-1110,坏块为 file # 4, block # 133

SQL> select * from dept;

 select * from dept

*

ERROR at line 1:

ORA-01578: ORACLE data block corrupted (file # 4, block # 133)

ORA-01110: data file 4: '/u01/app/oracle/oradata/orcl/users01.dbf'

3. 出现以上错误的同时在 alert log 中也有详细错误信息,这些错误信息说明数据块(file # 4, block # 133)损坏的原因是 checksum 无效。数据块中记录的 checksum 值为 0x8167(这个值是上一次 DBWR 写入磁盘时计算的),读取数据块时重新计算得到的 checksum 是0x8122,checksum值异或运算(Xor)的结果是0x45 ( computed block checksum )。由于两次 checksum 值不同(即异或结果为非0),说明数据块被修改过,数据块为坏块( corruption )。

Alert log错误信息:



4.1 对应的 orcl_ora_20892.trc 中也有数据块的信息,其中数据块上记录的 checksum 值是0x8167(chkval)

Block dump from disk:

buffer tsn: 4 rdba: 0x01000085 (4/133)

scn: 0x0000.0023d69a seq: 0x05 flg: 0x06 tail: 0xd69a0605

frmt: 0x02 chkval: 0x8167 type: 0x06=trans data

Hex dump of block: st=0, typ_found=1


4.2 通过dd也查看数据块中记录的 checksum 值, offset 16,17 对应的是 checksum 值 0x8167

$ dd if=/u01/app/oracle/oradata/orcl/users01.dbf bs=8192 count=1 skip=133 of=/tmp/dd133.out

$ od -x /tmp/dd133.out

0000000 a206 0000 0085 0100 d69a 0023 0000 0605

0000020 8167 0000 0001 0000 3807 0000 2fef 000c

^^^^

5. 修复数据坏块的方法可以通过备份恢复或者 DBMS_REPAIR.SKIP_CORRUPT_BLOCKS 跳过坏块。

5.1 方法#1 RMAN数据块恢复:

RMAN> run {blockrecover datafile 4 block 133;}

SQL> select * from dept;

      DEPTNO DNAME          LOC

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

        10 ACCOUNTING     DALIAN

        20 RESEARCH       DALLAS

        30 SALES              CHICAGO

        40 OPERATIONS     BOSTON

5.2 方法#2 DBMS_REPAIR.SKIP_CORRUPT_BLOCKS 跳过坏块,然后将 dept 表中的其他数据导出重建表

SQL> alter session set db_file_multiblock_read_count=1;

SQL> execute DBMS_REPAIR.SKIP_CORRUPT_BLOCKS('JAMES','DEPT'); 

SQL> create table dept_new as select * from dept;

---------The  End

如何加入"云和恩墨大讲堂"微信群

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多