当前位置: 首页 > article >正文

【资源损坏类故障】:详细了解坏块

目录

1、物理坏块与逻辑坏块

1.1、物理坏块

1.2、逻辑坏块

2、两个坏块相关的参数

2.1、db_block_checksum

2.2、db_block_checking

3、检测坏块 

3.1、告警日志

3.2、RMAN

3.3、ANALYZE

3.4、数据字典

3.5、DBVERIFY

4、修复坏块

4.1、RMAN修复

4.2、DBMS_REPAIR修复

4.3、BBED

5、写在最后


1、物理坏块与逻辑坏块

        将数据库比喻成一本书,每一页看作是一个数据块。当我们看不懂书中某页的内容可能有3种原因:该页缺损、该页内容逻辑有错误、智商不够。我们的智商显然不是问题,这点首先排除。

        所以书页缺损、书页上的内容逻辑错误是最可能的两点原因。其中页书缺损就好比数据库中的物理坏块,直接粗暴的破坏了这一页;书页上的内容逻辑错误就像是数据库中的逻辑坏块,写的内容驴头不对马嘴。

        如果现在写的这篇文章让您读着不通顺或者读不懂,那这篇文章也属于是个逻辑坏块。

1.1、物理坏块

        存储介质导致的数据块损坏,常见的场景是磁盘损坏、网络故障导致数据块在传输时发生损坏,突然断电导致数据块的元数据损坏。

1.1.1、物理坏块的常见错误表现

1.1.1.1、Fractured Block(断块)

        断块是指数据块不完整,块头信息与块尾信息不匹配。

Corrupt block relative dba: 0x0380e573 (file 14, block 58739)

Fractured block found during buffer read

Data in bad block -

type: 6 format: 2 rdba: 0x0380e573

last change scn: 0x0288.8e5a2f78 seq: 0x1 flg: 0x04

consistency value in tail: 0x00780601

check value in block header: 0x8739, computed block checksum: 0x2f00

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

***

Reread of rdba: 0x0380e573 (file 14, block 58739) found same corrupted data

1.1.1.2、Bad checksum

        这个错误是指checksum不一致。

        checksum是数据块的校验和,它是Oracle将数据块中的内容通某种算法进行计算生成的一个唯一的校验值。checksum存储在数据块的头部;当读取数据块时,Oracle会重新计算checksum,与存储在数据块头部的checksum进行比较,如果不一致,就判断数据块发生了损坏。

Corrupt block relative dba: 0x0380a58f (file 14, block 42383)

Bad check value found during buffer read

Data in bad block -

type: 6 format: 2 rdba: 0x0380a58f

last change scn: 0x0288.7784c5ee seq: 0x1 flg: 0x06

consistency value in tail: 0xc5ee0601

check value in block header: 0x68a7, computed block checksum: 0x2f00

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

***

Reread of rdba: 0x0380a58f (file 14, block 42383) found same corrupted data

1.1.1.3、Block Misplaced

        Oracle检测到正在读取的数据块的内容属于另一个块,但是checksum有效。

 Corrupt block relative dba: 0x0d805a89 (file 54, block 23177)

Bad header found during buffer read

Data in bad block -

type: 6 format: 2 rdba: 0x0d805b08 ----> Block is different than expected 0x0d805a89

last change scn: 0x0692.86dc08e3 seq: 0x1 flg: 0x04

consistency value in tail: 0x08e30601

check value in block header: 0x2a6e, computed block checksum: 0x0

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

1.1.1.4、Zeroed out blocks

        如果Oracle数据库发生了Zeroed out blocks,那么基本可以判断是操作系统或者存储系统发生了故障。

        根据Oracle官方文档描述,在设计的时候,Oracle就被确定不会写全零块,目的是为了识别底层操作系统或者存储中的故障。

Corrupt block relative dba: 0x014000a0 (file 5, block 160)

Completely zero block found during multiblock buffer read

1.2、逻辑坏块

        逻辑坏块是指数据块的内容或者结构不符合Oracle内部规范,但是在物理存储介质方面没有问题。虽然发生了逻辑坏块,但其checksum很可能并无问题,只是数据块中的内容发生了损坏。

        逻辑坏块的详细损坏描述通常不会输出到告警日志中,这点是和物理坏块不同的。

1.2.1、逻辑坏块常见错误表现:

1.2.1.1、ORA-600 [4512]

ORA-600 [4512],被不存在的事务锁定了行。

1.2.1.2、不符合自然逻辑

日期数据类型字段,存入了2025-03-32 25:61:61这种不符合自然逻辑的数据。

1.2.1.3、数据字典逻辑损坏

Oracle数据字典字典表发生了字典数据与实际不一致的情况;例如:dba_tables显示某表存在,但是实际的数据文件没有这个表段。

执行DDL操作时,触发ORA-00600 [kdsgrp1],或者元数据查询失败。

1.2.1.4、索引失效

索引指向了无效的ROWID,比如说数据行已经被删除了,但是索引没有更新。

索引扫描时,返回ORA-01410(无效的ROWID),或者查询结果不匹配。

1.2.1.5、数据块头部元数据损坏

数据块的头部信息,例如块的类型、SCN、事务槽遭到损坏。例如数据块的类型本来是表段块,但是实际存储的却是索引,这种错误就属于是Oracle软件的bug了。

访问到这种逻辑坏块时,触发ORA-00600 [kddummy_blkchk]内部错误。


2、两个坏块相关的参数

2.1、db_block_checksum

        这个参数是用来控制checksum的生成.

        checksum是数据块的校验和,它是Oracle将数据块中的内容通某种算法进行计算生成的一个唯一的校验值。checksum存储在数据块的头部;当读取数据块时,Oracle会重新计算checksum,与存储在数据块头部的checksum进行比较,如果不一致,就判断数据块发生了损坏。

        可以通过show parameter来查看当前数据库对于此参数的配置情况。

SQL> show parameter db_block_checksum

NAME				     TYPE	 VALUE
------------------------------------ ----------- ------------------------------
db_block_checksum		     string	 TYPICAL

        db_block_checksum参数有3种选项:FULL、TYPICAL、OFF,下面对这三种选项进行简单说明。

参数选项简单说明
FULL对所有数据块,包括数据文件、控制文件、日志文件生成校验和。
TYPICAL默认值,对数据文件、控制文件生成校验和,不会作用于临时表空间。
OFF不生成checksum,这个是不推荐的。

        可以修改db_block_checksum参数,但因为是静态参数,修改完参数需要重启数据库。

ALTER SYSTEM SET db_block_checksum = FULL SCOPE=SPFILE;

2.2、db_block_checking

        这个参数是对数据块的逻辑一致性检查,当数据块在被读取或者修改时,自动检测数据块内部结构的逻辑错误,从而防止因为逻辑损坏导致数据丢失。

        db_block_checking参数有4种选项:HIGH、MEDIUM、LOW、OFF,下面对这4种选项进行简单的说明。

参数选项简单说明
HIGH执行完整的逻辑检查,包括索引块、事务槽,覆盖数据库所有的修改操作。
MEDIUM对所有表空间的数据块执行基本检查,例如块头等。
LOW只对数据库的系统表空间执行数据块检查。
OFF不对任何数据块执行检查,这是个默认值。

        可以修改db_block_checking参数,但因为是静态参数,修改完参数需要重启数据库。

ALTER SYSTEM SET db_block_checking=HIGH SCOPE=SPFILE;

       db_block_checksum与db_block_checking参数的不同点在于db_block_checksum是用来检测物理完整性的,主要是服务于物理坏块问题处理;db_block_checking是用来检测逻辑一致性的,主要是服务于逻辑坏块问题处理。

        db_block_checksum与db_block_checking参数的相同点是当启用参数时,启用的级别的越高,对性能的影响就会越大。所以在使用这两个参数时,需要在数据库性能和数据安全这两方面做好平衡。


3、检测坏块 

        Oracle数据库提供了几种手段可以对坏块进行监测,下面对这些手段进行逐一介绍。这些手段侧重点和使用场景都有不同,有的也可以组合使用,效率效果更佳。

3.1、告警日志

        告警日志是DBA最常看的日志,每次巡检如果绕开它,个人觉得都不算一次标准的巡检。Oracle在检测到数据坏块时,会在告警日志中记录错误信息。通过检查告警日志,可以及时发现数据坏块错误。

        确定告警日志位置,以下两个方法都可以。

SQL> show parameter dump

NAME				     TYPE	 VALUE
------------------------------------ ----------- ------------------------------
background_core_dump		     string	 partial
background_dump_dest		     string	 /oracle/app/diag/rdbms/htbase/htbase1/trace
core_dump_dest			         string	 /oracle/app/diag/rdbms/htbase/htbase1/cdump
max_dump_file_size		         string	 unlimited
shadow_core_dump		         string	 PARTIAL
user_dump_dest			         string	 /oracle/app/diag/rdbms/htbase/htbase1/trace


SQL> SELECT value FROM v$diag_info WHERE name = 'Diag Trace';

VALUE
--------------------------------------------------------------------------------
/oracle/app/diag/rdbms/htbase/htbase1/trace

        检索坏块错误记录

        在告警日志中搜索“ORA-01578”,或者搜素“Corrupt block“关键字。这个大家可以看上文物理坏块介绍那里就知道为什么检索两个了。

3.2、RMAN

        RMAN也是官方推荐坏块检测工具,支持对数据文件、控制文件、归档日志文件等进行完整性检查,个人觉得RMAN比较适合作为一种定期健康检查的手段。RMAN有下面几种检查方式。

3.2.1、检查整个数据库

        可以输出所有数据文件、控制文件、日志文件的坏块信息。

RMAN> VALIDATE DATABASE;

3.2.2、检查指定的数据文件

        可以输出数据文件内每个块的物理和逻辑一致性。

RMAN> VALIDATE DATAFILE 28;  -- 文件号为28的数据文件

3.2.3、逻辑一致性检查

        不仅检查数据块的物理完整性,还会检查数据块的逻辑结构。

RMAN> VALIDATE CHECK LOGICAL DATABASE;

3.2.4、检查备份集

        这个命令,无论是新手还是老手都不陌生,备份常用命令,检查备份文件是否损坏,确保恢复的时候是可用的。

RMAN> VALIDATE BACKUPSET <备份集编号>;

3.3、ANALYZE

ANALYZE命令可以检查表、索引的逻辑一致性。

3.3.1、检查表结构

        如果存在坏块,会抛出ORA-01498错误。此时可能是数据块头部的元数据信息出错、索引对应数据块的关联关系有误(这些都在上文的逻辑坏块部分介绍过);如果是物理坏块,还会伴随着ORA-01578。

ANALYZE TABLE hr.zqd VALIDATE STRUCTURE;

3.3.2、检查索引的一致性

        如果索引与表数据不匹配,会抛出ORA-01499错误。这可能是索引和表数据没同步,例如删除大量数据后,没有重建索引;事务异常中断导致索引条目没有正常更新等等。如果是物理损坏的话,会伴随着ORA-01578错误。

        此时比较高效的修复操作是重建索引,但不一定能解决所有场景下的此类问题。

ANALYZE INDEX HR.zqd_idx VALIDATE STRUCTURE;

3.4、数据字典

3.4.1、V$DATABASE_BLOCK_CORRUPTION

SELECT * FROM V$DATABASE_BLOCK_CORRUPTION;

        这个视图会记录Oracle数据库中检测到坏块信息。这个视图的数据写入触发机制包含以下几种途径。

操作具体操作
RAMN

1、使用RMAN进行备份的时候,会验证数据块的完整性,若发现坏块,会写入该视图。

2、使用RMAN进行VALIDATE验证时,若发现坏块,会写入该视图。

3、使用RMAN进行RECOVER恢复时,若发现坏块,会写入该视图。

进程检测

1、读取数据时,checksum不一致,会将坏块信息写入该视图。

2、SELECT语句访问到坏块时,会将坏块信息写入该视图。

工具检查

1、DBVERIFY作为外部工具,不会直接将坏块信息写入视图,但可以通过日志文件手动确认坏块后,需要通过数据库操作才会将坏块信息写入视图。

2、ANALYZE命令若检测到坏块可能会将坏块信息写入视图。

3.4.2、DBA_EXTENTS

        通过这个Oracle系统基础表,可以定位到具体的坏块所在对象,可能是表、索引、大字段。

SELECT owner, segment_name, segment_type
FROM dba_extents
WHERE file_id = 5    -- 文件号
  AND 1234 BETWEEN block_id AND block_id + blocks -1;  -- 块号

3.5、DBVERIFY

        DBVERIFY是Oracle数据库提供的命令行工具,用于检查数据文件物理和逻辑一致性,重点检查数据块的完整性。

3.5.1、DBVERIFY有几个特点,主要包含以下几个方面。

3.5.1.1、只读方式打开

        它以只读的方式打开数据文件,不会修改数据文件,确保了数据文件的安全性。

3.5.1.2、在线检查

        它支持在线检查数据文件,不需要关闭数据库。当然离线时对数据文件的检查速度更快。

3.5.1.3、支持对ASM文件的检查

        在数据库是正常打开的情况下,通过userid参数指定用户权限,即可检查ASM文件。

dbv file=+DG1/orcl/datafile/system01.dbf userid=system/sys

3.5.2、DBVERIFY是有局限性的,主要包含以下几个方面:

3.5.2.1、只检查数据文件

        它只能检查数据文件;不能检查控制文件和日志文件。

3.5.2.2、不检查逻辑关联性

        只会检查数据块内部的结构,不会检查索引与表数据的匹配关系。

3.5.2.3、文件大小限制

        在某些平台下,不能检查超过2G的数据文件(但这一点我自己没有实际验证过)。

3.5.3、常用与帮助

        DBVERIFY工具的命令参数有很多,但常用的就是FILE、BLOCKSIZE、LOGFILE等。如果有特殊需要可以查看帮助:dbv help=y

dbv FILE=/oradata/users01.dbf BLOCKSIZE=8192 LOGFILE=/tmp/dbv.log

4、修复坏块

4.1、RMAN修复

        最理想的是使用RMAN恢复,进而实现修复坏块的目的。但这是需要当前数据库有备份,并且备份可用无坏块的情况下。

4.1.1、使用RMAN进行块恢复

        检测到数据库的坏块、坏块所在数据文件后,可以指定坏块进行块恢复。建议是在数据库坏块不多的情况下使用块恢复,这种修复效率很高;如果是恢复整个数据文件,恢复效率会相对很低。

RMAN> VALIDATE BACKUPSET ALL; --检查所有备份集是否可用,且有无坏块。

RMAN> VALIDATE BACKUPSET <备份集编号>; --指定备份集进行检查,检查是否可用,且有无坏块。
RMAN> VALIDATE DATABASE; --检测坏块位置
RMAN> blockrecover datafile 4 block 1798; --进行块恢复

--也可以一次修复同一数据文件中的多个坏块
RMAN> blockrecover datafile 4 block 1798,1799; --进行多个坏块恢复
 VALIDATE DATAFILE 4 BLOCK 1798; --验证修复结果

4.1.2、使用RMAN进行数据文件恢复

        如果数据库中的坏块很多,或者进行RMAN块恢复失败时,可以尝试使用RMAN进行数据文件恢复。

        使用RMAN进行数据文件恢复会有几点事项需要注意:恢复期间,数据库部分不可用,因为坏块所在的数据文件需要OFFLINE;需要确保归档日志完整以支持完全恢复;如果坏块所在的数据文件比较大,恢复效率不会很高。

RMAN> VALIDATE BACKUPSET ALL; --检查所有备份集是否可用,且有无坏块。

RMAN> VALIDATE BACKUPSET <备份集编号>; --指定备份集进行检查,检查是否可用,且有无坏块。
RMAN> VALIDATE DATABASE; --检测坏块位置
SQL> ALTER DATABASE DATAFILE 4 OFFLINE; --离线坏块所在的数据文件
RMAN> RESTORE DATAFILE 4; --从备份恢复数据文件
RMAN> RECOVER DATAFILE 4; --还原坏块所在的数据文件
SQL> ALTER DATABASE DATAFILE 4 ONLINE; --切换数据文件为ONLINE状态。

4.1.3、补充

        上文的备份集检查是建议每次备份完就执行检查,定期巡检也加入这类检查。如果备份集不可用或者存在坏块,那么使用RMAN进行坏块修复的这条路就断掉了。

4.2、DBMS_REPAIR修复

        Oracle数据库提供了DBMS_REPAIR包用于修复坏块。但这个方法在修复坏块方面往往是不奏效的。拟人化的讲,我个人觉得这个DBMS包有点 “打的过就打,打不过就跑” 的感觉。因为它虽然很多时候修不好坏块,但是它能让Oracle的增删改查操作跳过坏块;这也就导致了使用DBMS_REPAIR方法非常可能会丢失数据。但是在没有备份的情况下,这也是发生坏块时,能拯救部分数据的方法之一。

        下图是DBMS_REPAIR的常用方法总结。

        现在Oracle数据库中HR.ZQD0318表有个坏块,接下来详细描述下DBMS_REPAIR修复/跳过坏块的步骤。

SQL> SELECT COUNT(*) FROM HR.ZQD0318;

  COUNT(*)
----------
     72594

4.2.1、创建REPAIR表

        REPAIR表用于记录需要被修复的表。REPAIR表创建完后,是不会立刻有数据的;在检查完对象的数据块受损情况后,REPAIR表才会有数据。

BEGIN
DBMS_REPAIR.ADMIN_TABLES(
    TABLE_NAME => 'REPAIR_TABLE',
    TABLE_TYPE => DBMS_REPAIR.REPAIR_TABLE,
    ACTION => DBMS_REPAIR.CREATE_ACTION,
    TABLESPACE => 'ZQD');
END;
--如果在SQLPLUS中执行PLSQL代码块,需要在代码块末尾加上“/”

4.2.2、 创建ORPHAN表

        ORPHAN表是用来存放在表出现坏块后的孤立(OPRHAN)索引相关信息,也就是指向那些坏块的索引信息。ORPHAN表创建完后,不会立刻有数据;在使用DUMP_ORPHAN_KEYS过程后,才会有指向坏块的索引相关信息。

BEGIN
    DBMS_REPAIR.ADMIN_TABLES(
    TABLE_NAME => 'ORPHAN_KEY_TABLE',
    TABLE_TYPE => DBMS_REPAIR.ORPHAN_TABLE,
    ACTION => DBMS_REPAIR.CREATE_ACTION,
    TABLESPACE => 'ZQD');
END;
--如果在SQLPLUS中执行PLSQL代码块,需要在代码块末尾加上“/”

4.2.3、检查对象的数据块受损情况

        检查完后,坏块信息会写入REPAIR表。

DECLARE
    corruptnum INT;
BEGIN
    corruptnum := 0;
    DBMS_REPAIR.CHECK_OBJECT(
        SCHEMA_NAME => 'HR',
        OBJECT_NAME => 'ZQD0318',
        REPAIR_TABLE_NAME => 'REPAIR_TABLE',
        CORRUPT_COUNT => corruptnum);
    DBMS_OUTPUT.PUT_LINE('坏块数量:' || TO_CHAR(corruptnum));
END;
--如果在SQLPLUS中执行PLSQL代码块,需要在代码块末尾加上“/”

4.2.4、查看坏块信息

SELECT OBJECT_NAME,BLOCK_ID,CORRUPT_TYPE,MARKED_CORRUPT,REPAIR_DESCRIPTION FROM REPAIR_TABLE;

4.2.5、尝试修复坏块

        如果输出是0,则说明修复了0个坏块,修复无效,此时可以选择跳过坏块。

DECLARE
fixnum number;
BEGIN
    DBMS_REPAIR.FIX_CORRUPT_BLOCKS(
        SCHEMA_NAME => 'HR',
        OBJECT_NAME => 'ZQD0318',
        FIX_COUNT => fixnum);
    DBMS_OUTPUT.PUT_LINE('修复坏块的数量:' || TO_CHAR(fixnum));
END;
--如果在SQLPLUS中执行PLSQL代码块,需要在代码块末尾加上“/”

4.2.6、 记录指向坏块的索引相关信息

        执行完如下的PLSQL代码块后,失效索引相关信息(指向坏块的索引相关信息)会写入ORPHAN表。PLSQL代码块中的OBJECT_NAME是索引的名字,不是表名;如果有多个索引,需要为每个索引执行DUMP_ORPHAN_KEYS操作。

DECLARE
    DATAS NUMBER;
BEGIN
    DBMS_REPAIR.DUMP_ORPHAN_KEYS(
        SCHEMA_NAME => 'HR',
        OBJECT_NAME => 'IDX_ZQD',
        OBJECT_TYPE => DBMS_REPAIR.INDEX_OBJECT,
        REPAIR_TABLE_NAME => 'REPAIR_TABLE',
        ORPHAN_TABLE_NAME => 'ORPHAN_KEY_TABLE',
        KEY_COUNT => COUNTS);
    DBMS_OUTPUT.PUT_LINE('孤立索引数量:' || TO_CHAR(COUNTS));
END;

4.2.7、跳过坏块

        执行下面PLSQL代码块后,坏块已被标记跳过。此时增删改查都不会报错,但坏块上的这部分数据也就丢失了。但丢失的数据的ROWID依然可以在ORPHAN表找到。

BEGIN
    DBMS_REPAIR.SKIP_CORRUPT_BLOCKS(
        SCHEMA_NAME => 'HR',
        OBJECT_NAME => 'ZQD0318',
        OBJECT_TYPE => DBMS_REPAIR.TABLE_OBJECT,
        FLAGS => DBMS_REPAIR.SKIP_FLAG);
END;
--如果在SQLPLUS中执行PLSQL代码块,需要在代码块末尾加上“/”

4.2.8、重建索引

ALTER INDEX HR.IDX_ZQD REBUILD

4.2.9、验证结果

SQL> SELECT COUNT(*) FROM HR.ZQD0318;

  COUNT(*)
----------
     72542

4.2.10、后续

        上面的一套组合拳打完,表虽然恢复了访问、但是也丢失了部分数据。即使丢失的数据可以通过其他方式补回来(例如数据仓库可以再重新抽取数据),也存在一个问题:坏块依然存在。

        此时,将表中的数据全部导出(导出时跳过了坏块数据),然后重建表;再将导出的数据重新导入到数据库中;这个过程建议是使用数据泵expdp/impdp操作。操作完毕后,可以彻底消除坏块。

4.3、BBED

        BBED:Block Browser and Editor(块浏览器和编辑器)

        BBED直接操作底层数据块,风险很高,需要非常专业的人士来操作。且操作不可逆,是作为坏块修复的最后一种手段使用。


5、写在最后

        上面简单介绍了坏块的3种修复手段;但当真在生产上遇到了坏块情况,仅凭这篇文章的描述,很难高效解决问题。这篇文章只是基础了解,想要高效解决坏块问题,除了基础以外,需要平时多做模拟演练,定期总结,才能在遇到坏块时,快速给出最完美的解决方案。


http://www.kler.cn/a/592258.html

相关文章:

  • 【从零开始学习计算机科学与技术】计算机网络(三)数据链路层
  • jmeter吞吐量控制器-Throughput Controller
  • 每月更新,提供qiime2兼容库:Mitohelper助力鱼类线粒体序列分析
  • PostgreSQL 14.17 安装 pgvector 扩展
  • Lambda 表达式的语法:
  • 高频SQL 50 题(持续更新)
  • 企业年度经营计划制定与管理方法论(124页PPT)(文末有下载方式)
  • Java:读取中文,read方法
  • WebAssembly 技术在逆向爬虫中的应用研究
  • 网络安全漏洞与修复 网络安全软件漏洞
  • 从位置编码开始手搓transformer框架,transfromer讲解
  • DeepSeek算力服务器的选型--青岛佰优联创新科技有限公司
  • HTML语言的贪心算法
  • Golang | 每日一练 (6)
  • 植物知识分享论坛毕设
  • 【QA】CRTP在模板中有哪些用处?
  • Ollama + Open WebUI 本地部署DeepSeek
  • test_cases测试用例层/test_1_login
  • 2023 CSP-J 题解
  • 蓝桥杯练习day2:执行操作后的变化量