Skip to content

坏块

检测坏块处于对象上面还是空闲空间的脚本

该脚本的作用为查找损坏的块是在对象上面还是在空闲空间上.

set lines 200 pages 10000
col segment_name format a30

SELECT e.owner, e.segment_type, e.segment_name, e.partition_name, c.file#
, greatest(e.block_id, c.block#) corr_start_block#
, least(e.block_id+e.blocks-1, c.block#+c.blocks-1) corr_end_block#
, least(e.block_id+e.blocks-1, c.block#+c.blocks-1)
- greatest(e.block_id, c.block#) + 1 blocks_corrupted
, null description
FROM dba_extents e, v$database_block_corruption c
WHERE e.file_id = c.file#
AND e.block_id <= c.block# + c.blocks - 1
AND e.block_id + e.blocks - 1 >= c.block#
UNION
SELECT s.owner, s.segment_type, s.segment_name, s.partition_name, c.file#
, header_block corr_start_block#
, header_block corr_end_block#
, 1 blocks_corrupted
, 'Segment Header' description
FROM dba_segments s, v$database_block_corruption c
WHERE s.header_file = c.file#
AND s.header_block between c.block# and c.block# + c.blocks - 1
UNION
SELECT null owner, null segment_type, null segment_name, null partition_name, c.file#
, greatest(f.block_id, c.block#) corr_start_block#
, least(f.block_id+f.blocks-1, c.block#+c.blocks-1) corr_end_block#
, least(f.block_id+f.blocks-1, c.block#+c.blocks-1)
- greatest(f.block_id, c.block#) + 1 blocks_corrupted
, 'Free Block' description
FROM dba_free_space f, v$database_block_corruption c
WHERE f.file_id = c.file#
AND f.block_id <= c.block# + c.blocks - 1
AND f.block_id + f.blocks - 1 >= c.block#
ORDER BY file#, corr_start_block#;

测试案例:

构造坏块

RMAN>  blockrecover datafile 4 block 20 clear;

Starting blockrecover at 28-SEP-15
using channel ORA_DISK_1
Finished blockrecover at 28-SEP-15

RMAN>  blockrecover datafile 4 block 22 clear;

Starting blockrecover at 28-SEP-15
using channel ORA_DISK_1
Finished blockrecover at 28-SEP-15

使用rman检测

RMAN> backup validate datafile 4;

Starting backup at 28-SEP-15
using target database control file instead of recovery catalog
allocated channel: ORA_DISK_1
channel ORA_DISK_1: sid=146 devtype=DISK
channel ORA_DISK_1: starting full datafile backupset
channel ORA_DISK_1: specifying datafile(s) in backupset
input datafile fno=00004 name=/luda/oracle/data/user01.dbf
channel ORA_DISK_1: backup set complete, elapsed time: -01:59:59
Finished backup at 28-SEP-15

执行该脚本查询坏块对应的对象

SQL> select * from v$database_block_corruption ;

     FILE#     BLOCK#     BLOCKS CORRUPTION_CHANGE# CORRUPTIO
---------- ---------- ---------- ------------------ ---------
         4         22          1                  0 CHECKSUM
         4         20          1                  0 CHECKSUM


SQL> set lines 200 pages 10000
SQL> col segment_name format a30
SQL>
SQL> SELECT e.owner, e.segment_type, e.segment_name, e.partition_name, c.file#
  2  , greatest(e.block_id, c.block#) corr_start_block#
  3  , least(e.block_id+e.blocks-1, c.block#+c.blocks-1) corr_end_block#
  4  , least(e.block_id+e.blocks-1, c.block#+c.blocks-1)
  5  - greatest(e.block_id, c.block#) + 1 blocks_corrupted
  6  , null description
  7  FROM dba_extents e, v$database_block_corruption c
  8  WHERE e.file_id = c.file#
  9  AND e.block_id < = c.block# + c.blocks - 1
 10  AND e.block_id + e.blocks - 1 >= c.block#
 11  UNION
 12  SELECT s.owner, s.segment_type, s.segment_name, s.partition_name, c.file#
 13  , header_block corr_start_block#
 14  , header_block corr_end_block#
 15  , 1 blocks_corrupted
 16  , 'Segment Header' description
 17  FROM dba_segments s, v$database_block_corruption c
 18  WHERE s.header_file = c.file#
 19  AND s.header_block between c.block# and c.block# + c.blocks - 1
 20  UNION
 21  SELECT null owner, null segment_type, null segment_name, null partition_name, c.file#
 22  , greatest(f.block_id, c.block#) corr_start_block#
 23  , least(f.block_id+f.blocks-1, c.block#+c.blocks-1) corr_end_block#
 24  , least(f.block_id+f.blocks-1, c.block#+c.blocks-1)
 25  - greatest(f.block_id, c.block#) + 1 blocks_corrupted
 26  , 'Free Block' description
 27  FROM dba_free_space f, v$database_block_corruption c
 28  WHERE f.file_id = c.file#
 29  AND f.block_id < = c.block# + c.blocks - 1
 30  AND f.block_id + f.blocks - 1 >= c.block#
 31  ORDER BY file#, corr_start_block#;

OWNER                          SEGMENT_TYPE       SEGME PARTITION_NAME                      FILE# CORR_START_BLOCK# CORR_END_BLOCK# BLOCKS_CORRUPTED DESCRIPTION
------------------------------ ------------------ ----- ------------------------------ ---------- ----------------- --------------- ---------------- --------------
SYS                            TABLE              LUDA                                          4                20              20                1
SYS                            TABLE              LUDA                                          4                22              22                1

浅谈Oracle数据库坏块( Database corruption part 1 )

关于坏块这一类的故障,从业这些年遇见得比较多,有的数据还能抢救,有的数据直接就丢了,更甚者数据库因此报废了. 一旦碰到,虽说不一定棘手,但是不免心里求佛一翻.

所谓Oracle数据库坏块顾名思义oracle数据库所在的数据存储介质的内容出现了讹误混乱或者无法访问.在Oracle自己的范围内对坏块有定义,这个可以参考文档[Note 840978.1].

坏块的种类有很多,它有可能因为各种原因出现在Oracle database的几种文件上面,报错也因此各有差异,处理的手段方法也各不相同,很早之前我就承诺过对这部分内容进行梳理更新到ludatou.com上,而现在我和陈辉正在对Mdata针对坏块部分的处理在做研发.所以趁此机会也尽量将文章更新到博客上,大部分上会是原创,有好的文章我也会转发.浅谈坏块这一系列的文章以方法和原理为主,除此之外我会把以往的坏块处理案例以日志方式更新,不作为浅谈部分文章.

浅谈坏块内容主要包含以下几部分:

    坏块分类以及产生的主要原因
    坏块的构造,检测方法以及可能发生的Oracle文件
    坏块的主要错误以及处理方法
    坏块的预防方式

本篇为坏块分类以及产生的主要原因

————————————————

1.坏块的主要分类,来自Oracle官方文档的解释,有助于更直接的了解区分物理坏块和逻辑坏块的区别(Note 840978.1有更加详细的描述):

For purposes of the paper we will categorize corruption under three general areasand give best practices for prevention, detection and repair for each:

    Memory corruption
    Logical corruption(soft corruption)
    Media corruption(Physicalcorruption)

Physicalor structural corruption can be defined as damage to internal data structureswhich do not allow Oracle software to find user data within the database. Logical corruption involves Oracle beingable to find the data, but the data values are incorrect as far as the end useris concerned.
Physica lcorruption due to hardware or software can occur in two general places — inmemory (including various IO buffers and the Oracle buffer cache) or on disk.Operator error such as overwriting a file can also be defined as a physicalcorruption. Logical corruption on theother hand is usually due to end-user error or non-robust(?) applicationdesign. A small physical corruption such as a single bit flip may be mistakenfor a logical error.

2.坏块的产生主要原因
坏块产生的原因很多 ,这里根据资料整理以及历史遭遇梳理出主要产生数据库坏块的原因.

    2.1 硬件问题
    Oracle进程在处理一个数据块时,首先将其读入物理内存空间,在处理完成后,再由特定进程将其写回磁盘;如果在这个过程中,出现内存故障,CPU计算失误,都会导致内存数据块的内容混乱,最后反映到写回磁盘的数据块内容有误。同样,如果存储子系统出现异常,数据块损坏也就随之出现了。比如硬盘出现坏道,那么这部分的数据就处于无法读取的情况,和坏块没有区别.

    2.2 操作系统BUG
    由于Oracle进程对数据块的读写,都是以操作系统内核调用(system call)的方式完成的,如果操作系统在内核调用存在问题,必然导致Oracle进程写入非法的内容。

    2.3 操作系统的I/O错误或缓冲问题
    比如写丢失,io系统缓存掉电,io操作结果被截断

    2.4 内存或paging问题
    Oracle软件有较多的bug能导致坏块问题的出现,

    2.5 非Oracle进程扰乱Oracle共享内存区域
    如上文所述,在当数据块的内容被读入主机的物理内存时,如果其他非Oracle进程,对Oracle使用的共享内存区域形成了扰乱,最终导致写回磁盘的数据块内容混乱。

    2.6 异常关机,掉电,终止服务
    异常关机,掉电,终止服务使进程异常终止,也会导致坏块产生。

    2.7 数据库操作人为失误
    使用nologging选项操作后再做恢复后可能造成坏块,或者人为的破坏文件导致的坏块。

Oracle坏块常见错误

ORA-1578

ORA-1578 is reported when a block is thought to be corrupt on read.

ORA-1410

This error is raised when an operation refers to a ROWID in a table for which there is no such row.
The reference to a ROWID may be implicit from a WHERE CURRENT OF clause or directly from a WHERE ROWID=… clause.
ORA 1410 indicates the ROWID is for a BLOCK that is not part of this table.

ORA-8103

The object has been deleted by another user since the operation began.
If the error is reproducible, following may be the reasons:-
a.) The header block has an invalid block type.
b.) The data_object_id (seg/obj) stored in the block is different than the data_object_id stored in the segment header. See dba_objects.data_object_id and compare it to the decimal value stored in the block (field seg/obj).

ORA-8102

An ORA-08102 indicates that there is a mismatch between the key(s) stored in the index and the values stored in the table. What typically happens is the index is built and at some future time, some type of corruption occurs, either in the table or index, to cause the mismatch.

ORA-1498

Generally this is a result of an ANALYZE … VALIDATE … command.
This error generally manifests itself when there is inconsistency in the data/Index block. Some of the block check errors that may be found:-
a.) Row locked by a non-existent transaction
b.) The amount of space used is not equal to block size
c.) Transaction header lock count mismatch.
While support are processing the tracefile it may be worth the re-running the ANALYZE after restarting the database to help show if the corruption is consistent or if it ‘moves’.
Send the tracefile to support for analysis.
If the ANALYZE was against an index you should check the whole object. Eg: Find the tablename and execute:
ANALYZE TABLE xxx VALIDATE STRUCTURE CASCADE;

ORA-1499

An error occurred when validating an index or a table using the ANALYZE command.
One or more entries does not point to the appropriate cross-reference.

ORA-26040

Trying to access data in block that was loaded without redo generation using the NOLOGGING/UNRECOVERABLE option.
This Error raises always together with ORA-1578

ORA-600 [12700]

Oracle is trying to access a row using its ROWID, which has been obtained from an index.
A mismatch was found between the index rowid and the data block it is pointing to. The rowid points to a non-existent row in the data block. The corruption can be in data and/or index blocks.
ORA-600 [12700] can also be reported due to a consistent read (CR) problem.

ORA-600 [3020]

This is called a ‘STUCK RECOVERY’.
There is an inconsistency between the information stored in the redo and the information stored in a database block being recovered.

ORA-600 [4194]

A mismatch has been detected between Redo records and rollback (Undo) records.
We are validating the Undo record number relating to the change being applied against the maximum undo record number recorded in the undo block.
This error is reported when the validation fails.

ORA-600 [4193]

A mismatch has been detected between Redo records and Rollback (Undo) records.
We are validating the Undo block sequence number in the undo block against the Redo block sequence number relating to the change being applied.
This error is reported when this validation fails.

ORA-600 [4137]

While backing out an undo record (i.e. at the time of rollback) we found a transaction id mis-match indicating either a corruption in the rollback segment or corruption in an object which the rollback segment is trying to apply undo records on.
This would indicate a corrupted rollback segment.

ORA-600 [6101]

Not enough free space was found when inserting a row into an index leaf block during the application of undo.

ORA-600 [2103]

Oracle is attempting to read or update a generic entry in the control file.
If the entry number is invalid, ORA-600 [2130] is logged.

ORA-600 [4512]

Oracle is checking the status of transaction locks within a block.
If the lock number is greater than the number of lock entries, ORA-600 [4512] is reported followed by a stack trace, process state and block dump.
This error possibly indicates a block corruption.

ORA-600 [2662]

A data block SCN is ahead of the current SCN.
The ORA-600 [2662] occurs when an SCN is compared to the dependent SCN stored in a UGA variable.
If the SCN is less than the dependent SCN then we signal the ORA-600 [2662] internal error.

ORA-600 [4097]

We are accessing a rollback segment header to see if a transaction has been committed.
However, the xid given is in the future of the transaction table.
This could be due to a rollback segment corruption issue OR you might be hitting the following known problem.

ORA-600 [4000]

It means that Oracle has tried to find an undo segment number in the dictionary cache and failed.

ORA-600 [6006]

Oracle is undoing an index leaf key operation. If the key is not found, ORA-00600 [6006] is logged.
ORA-600[6006] is usually caused by a media corruption problem related to either a lost write to disk or a corruption on disk.

ORA-600 [4552]

This assertion is raised because we are trying to unlock the rows in a block, but receive an incorrect block type.
The second argument is the block type received.

ORA-600[6856]

Oracle is checking that the row slot we are about to free is not already on the free list.
This internal error is raised when this check fails.

ORA-600[13011]

During a delete operation we are deleting from a view via an instead-of trigger or an Index organized table and have exceeded a 5000 pass count when we raise this exception.

ORA-600[13013]

During the execution of an UPDATE statement, after several attempts (Arg [a] passcount) we are unable to get a stable set of rows that conform to the WHERE clause.

ORA-600[13030]

ORA-600[25012]

We are trying to generate the absolute file number given a tablespace number and relative file number and cannot find a matching file number or the file number is zero.

ORA-600[25026]

Looking up/checking a tablespace
invalid tablespace ID and/or rdba found

ORA-600[25027]

Invalid tsn and/or rfn found

ORA-600 [kcbz_check_objd_typ_3]

An object block buffer in memory is checked and is found to have the wrong object id. This is most likely due to corruption.

ORA-600[kddummy_blkchk] &ORA-600[kdblkcheckerror]

ORA-600[kddummy_blkchk] is for 10.1/10.2 and ORA-600[kdblkcheckerror] for 11 onwards.

ORA-600[ktadrprc-1]

ORA-600[ktsircinfo_num1]

This exception occurs when there are problems obtaining the row cache information correctly from sys.seg$. In most cases there is no information in sys.seg$.

ORA-600[qertbfetchbyrowid]

ORA-600[ktbdchk1-bad dscn]

This exception is raised when we are performing a sanity check on the dependent SCN and fail.
The dependent scn is greater than the current scn.

处理 Oracle7/8/8i/9i/10g/11g 中的 Oracle 块损坏(转)

本文章讨论如何处理 Oracle 数据文件中的一个或多个坏块,并介绍了处理这些坏块的主要方法。在采取任何措施之前,请先阅读完整篇文章。
本文档未介绍内存坏块问题(通常为 ORA-600 [17xxx] 类型错误)。

注意: 如果在启动时出现 ORA-1578 问题,请与当地支持中心联系,以获得参考建议。

本文章介绍了许多类型的错误,很多其他地方也可能引用到本文章。重要的是,您需要知道关于每个坏块的以下信息:

包含坏块的文件的绝对文件编号 (FILE NUMBER)。本文中称为“&AFN”。包含坏块的文件的名称。本文中称为“&FILENAME”。

如果您知道文件编号,但不知道文件名,则可以使用 V$DATAFILE 来获取文件名:
SELECT name FROM v$datafile WHERE file#=&AFN;

如果文件号未显示在 Oracle8i 的 V$DATAFILE 中,且 &AFN 大于 DB_FILES 参数值,则该文件可能是临时文件。在这种情况下,可以使用以下查询找到文件名:
SELECT name FROM v$tempfile WHERE file#=(&AFN – &DB_FILES_value);

文件中坏块的块编号。本文中称为“&BL”。包含受影响块的表空间编号和名称。

本文中称为“&TSN”(表空间编号)和“&TABLESPACE_NAME”。

如果您不知道这些信息,请使用以下查询找到它们:
SELECT ts# “TSN” FROM v$datafile WHERE file#=&AFN;
SELECT tablespace_name FROM dba_data_files WHERE file_id=&AFN;
表空间中的坏块大小。本文中称为“&TS_BLOCK_SIZE”。

SELECT block_size FROM dba_tablespaces
WHERE tablespace_name =
(SELECT tablespace_name FROM dba_data_files WHERE file_id=&AFN);
对于 Oracle 7、8.0 和 8.1:

数据库中所有表空间使用相同的块大小。
对于这些版本,使用命令”SHOW PARAMETER DB_BLOCK_SIZE” 返回的值作为 “ &TS_BLOCK_SIZE”

例如:对于 ORA-1578 错误:

ORA-01578: ORACLE data block corrupted (file # 7, block # 12698)
ORA-01110: data file 22: ‘/oracle1/oradata/V816/oradata/V816/users01.dbf’
那么:

&AFN 为 “22” (从错误 ORA-1110 部分获得)
&RFN 为 “7” (从错误 ORA-1578 的”file #”部分获得)
&BL 为 “12698” (从错误 ORA-1578 的”block #”部分获得)
&FILENAME 为 ‘/oracle1/oradata/V816/oradata/V816/users01.dbf’
&TSN 及其他信息可以从上面提到的 SQL 语句获得

对于其他错误(ORA-600、ORA-1498 等),上述值应由 Oracle Support 提供给您,或从涵盖相关错误的文章中获取。
对于某些错误,如 ORA-1410“invalid ROWID(无效 ROWID)”、ORA-12899“value too large for column(列值过大)”等,未给出损坏的文件/块的详细信息。对于此类情况, Note:869305.1 可以帮助您定位损坏的行。

概述处理坏块的步骤

有多种原因可能导致坏块,包括:

坏的 IO 硬件/固件
OS 问题
Oracle 问题
对于执行过“UNRECOVERABLE”或“NOLOGGING”操作的数据库进行恢复
(在这种情况下可能产生 ORA-1578 错误 – 如下方所示)
产生 Oracle 错误的时间点可能要比最初发生任何块损坏的时间点晚得多。

在遇到坏块时,我们通常无从了解根本原因,并且在大多数情况下,当下最迫切的需求是重新启动数据库并使其运行起来,正因如此,本文将介绍用于解决坏块问题的步骤,如下所列:

确定坏块问题的范围,并确定这些问题是持久性问题还是暂时性问题。
如果问题涉及范围很大,或错误不稳定,则关键在于先识别原因(检查硬件等)。这点很重要,因为如果是底层硬件出现错误,恢复系统便毫无意义。

更换或拆下任何有问题的或可疑的硬件。
确定哪些数据库对象受到影响。
选择最合适的数据库恢复/数据抢救选项。
对于上述所有步骤,最好应收集证据并详细记录所采取的措施。本文中的“证据>>”标签列出了应收集的信息,以帮助您识别问题的根本原因。

由于 NOLOGGING 或 UNRECOVERABLE 操作导致的坏块

如果对某个对象执行了 NOLOGGING(或 UNRECOVERABLE)操作,随后又恢复了包含该对象的数据文件,则受到 NOLOGGING 操作影响的数据块将被标记为“坏块”,当您访问该数据块时将显示 ORA-1578 错误。
NOLOGGING option(数据块使用 NOLOGGING 选项加载)”,此时原因一目了然,而较早版本中则没有附加这条错误消息。如果坏块是由于对执行过 NOLOGGING 操作的数据文件进行恢复而产生的,则可以使用本文中从 Section 3 “Information to Record for Each Corruption” 开始之后介绍的内容,但请注意以下问题:

恢复操作无法找回受 NOLOGGING 操作影响的数据
块内的数据无法抢救

(1) 确定坏块问题的范围

每次发生坏块错误时,都应记下完整的错误消息,并查看该实例的告警日志和跟踪文件,以了解任何相关的错误。首先进行这些步骤非常重要,这可以评估该损坏是单个块,还是由于 UNRECOVERABLE 操作产生的错误,抑或是更严重的问题。
使用 DBVERIFY 扫描受影响的文件(以及一切重要的文件)也是不错的办法,这样可以检查是否有其他坏块,从而确定问题的范围。有关使用 DBVERIFY 的详细信息,请参阅 Note:35512.1

一旦确定了损坏的文件/块组合列表,即可使用以下步骤来帮助确定应采取何种措施。

证据:
完整记录初始错误,以及发生错误的应用程序的详细信息。
及时地保存从告警日志中首次 (FIRST) 记录到问题前数小时到当前时间点所提取的内容。
保存告警日志中提到的任何跟踪文件。
记录最近遇到的任何 OS 问题。
记录是否正在使用任何特殊功能,例如:ASYNC IO、快速写入磁盘选项等。
记录当前的备份位置(日期、类型等)
记录数据库是否处于 ARCHIVELOG 模式,
例如:在SQL*Plus(或 Server Manager)中运行“ARCHIVE LOG LIST”

(2) 更换或拆下可疑硬件

大多数坏块问题是由故障硬件导致的。
如果出现硬件错误或可疑组件,最好进行修复,或者在执行恢复操作之前,确保在单独的磁盘子系统上有足够的可用空间用于恢复。

您可以使用以下步骤移动数据文件:

确保要迁移的文件已离线或数据库实例处于 MOUNT 状态(未打开)
将该数据文件物理还原(或复制)到新位置
例如:/newlocation/myfile.dbf
将该文件的新位置告知 Oracle。
例如:ALTER DATABASE RENAME FILE ‘/oldlocation/myfile.dbf’ TO ‘/newlocation/myfile.dbf’;
(请注意,您不能对临时文件进行重命名,而应删除临时文件并在新位置重新创建)
重要信息: 如果存在多个错误(不是由于 NOLOGGING操作导致的)
或 受影响文件所在的 OS 层面出现错误
或 错误是暂时性的且游离不定,
那么,如果不解决底层问题或准备另外的磁盘空间,那么进行任何操作都是毫无意义的。
与硬件供应商联系,以全面检查系统,并联系 Oracle Support,告知所有错误详情。
请注意: 如果硬件检查失败,即表明存在硬件问题,但硬件检查成功通过却并不能证明没有硬件相关问题 — 硬件测试报告成功但确实存在底层错误,这种情况也是经常发生。
如果使用了任何特殊 IO 选项,例如 direct IO、async IO 或类似的选项,最好将其禁用,以消除这些选项成为潜在问题原因的可能性。

(3) 每次坏块需记录的信息

在决定如何恢复之前,最好先确定哪些对象受到了影响,因为坏块可能发生在那些容易被重新创建的对象中。
例如:对于只有 5 行数据的表中发生的坏块,删除并重新创建表可能要比执行恢复快得多。

对于每个坏块,请收集下表中的信息。
进行此操作的步骤如下所述。

针对每次坏块需记录的信息
初始错误
绝对文件号

&AFN

相关文件号

&RFN

块编号

&BL

表空间 段类型 段
所有者.名称 相关对象 恢复选项
下列说明将有助于您针对每个坏块填写此表。

“初始错误”最初报告的错误。例如:ORA-1578/ORA-1110、ORA-600 和所有参数等。
“绝对文件号”, “相关文件号”和”块号”文件号和块号应该已在错误中显示,或由 Oracle Support 提供,或在指引您参考本文章的其他文章的步骤中提供。
在 Oracle8/8i/9i/10g 中: 绝对文件号和相关文件号通常是一样的,但也可能不同(尤其是在数据库是由 Oracle7 迁移而来的情况下)。请务必获得正确的 &AFN 和 &RFN 编号,否则您可能最终抢救的是错误的对象!!
ORA-1578 报告相关文件号,绝对文件号在伴随的 ORA-1110 错误中显示。对于 ORA-600 错误,您应该会被告知绝对文件号。
下列查询将显示数据库中数据文件的绝对和相关文件号:
SELECT tablespace_name, file_id “AFN”, relative_fno “RFN” FROM dba_data_files;[Insert code here. Use ‘Paste from Word’ to retain layout.]
在 Oracle8i/9i/10g 中:
除了上述关于 Oracle8 的说明外,从 Oracle8i 开始将拥有临时文件。下列查询将显示数据库中临时文件的绝对和相关文件号:
SELECT tablespace_name, file_id+value “AFN”, relative_fno “RFN” FROM dba_temp_files, v$parameter WHERE name=’db_files
在 Oracle7 中: “绝对文件号”和“相关文件号”使用相同的文件号
“段类型”, “所有者”, “名称”和”表空间”
在给定坏块的绝对文件号“&AFN”和块编号“&B”的情况下,下列查询将显示对象的段类型、所有者和名称,数据库必须打开才能使用此查询:
SELECT tablespace_name, segment_type, owner, segment_name FROM dba_extents
WHERE file_id = &AFN
and &BL between block_id AND block_id + blocks – 1;
如果坏块位于临时文件中,则上述查询将不会返回任何数据。
对于临时文件,“段类型”应为“TEMPORARY”。

如果上述查询未返回行,也可能是因为坏块是本地管理表空间 (Locally Managed Tablespace, LMT) 中的段头。当坏块为 LMT 中的段头块时,上述查询将在 alert.log 中生成一个坏块消息,但查询不会失败。在这种情况下,请使用以下查询:
SELECT owner, segment_name, segment_type, partition_name
FROM dba_segments
WHERE header_file = &AFN
and header_block = &BL;
{go to content}

(4) Which Object is affected and 可能的恢复选项:

相关对象和能够使用的恢复选项取决于 SEGMENT_TYPE。对于各种最常见的段类型,其他查询和可能的恢复选项如下所列。

CACHE
CLUSTER
INDEX PARTITION
INDEX
LOBINDEX
LOBSEGMENT
ROLLBACK
TABLE PARTITION
TABLE
TEMPORARY
TYPE2 UNDO
Some other Segment Type
“no rows” from the query

CACHE

如果段类型为 CACHE,请再次检查您是否输入了正确的 SQL语句和参数。
如果仍得到相同结果,请联系 Oracle Support 并上传您所了解的全部信息。

选项:可能需要恢复数据库。

{Continue} {Back to Segment List}

CLUSTER

如果段类型为 CLUSTER,则应确定它包含哪些表。

例如: SELECT owner, table_name fROM dba_tables WHERE owner=’&OWNER’ AND cluster_name=’&SEGMENT_NAME’;
选项:
如果所有者为“SYS”,则联系 Oracle Support 并上传所有详细信息。
可能需要恢复数据库。
对于非数据字典 cluster,可能的选项包括:

恢复
或 抢救 cluster 中所有表的数据
然后 重新创建 cluster 及其所有表

cluster 可能包含多个表,因此在做出决策之前,最好先收集 cluster 中每个表的信息。

{Collect TABLE information} {Back to Segment List}

INDEX PARTITION

如果段类型为 INDEX PARTITION,请记录名称和所有者,然后确定哪些分区受到影响:

SELECT partition_name
FROM dba_extents
WHERE file_id = &AFN AND &BL BETWEEN block_id AND block_id + blocks – 1
选项:
使用下列语句可以重建索引分区:
ALTER INDEX xxx REBUILD PARTITION ppp;
(请注意下方“重建索引”中所述的 REBUILD 选项)

{Continue} {Back to Segment List}

INDEX

如果段类型为 INDEX,而且所有者为“SYS”,则联系 Oracle Support 并上传所有详细信息。
对于非字典 INDEX 或 INDEX PARTITION,确定索引位于哪个表中:

SELECT table_owner, table_name
FROM dba_indexes
WHERE owner=’&OWNER’ AND index_name=’&SEGMENT_NAME’;
CONSTRAINT_TYPE 的可能值包括:
– P 索引支持主键约束。
– U 索引支持唯一约束。
如果索引支持主键约束(类型“P”),则确认主键是否被任何外键约束引用:

SELECT owner, constraint_name, constraint_type, table_name
FROM dba_constraints
WHERE r_owner=’&TABLE_OWNER’ AND r_constraint_name=’&INDEX_NAME’;
选项:
如果所有者为“SYS”,则联系 Oracle Support 并上传所有详细信息。
可能需要恢复数据库。

对于非字典索引,可能的选项包括:

恢复
或 重建索引(任何相关联的约束会随之禁用/启用)
(请注意下方”重建索引”中所述的 REBUILD 选项)

{Continue} {Back to Segment List}

ROLLBACK

如果段类型为 ROLLBACK,请联系 Oracle Support,因为 ROLLBACK 段坏块需要特殊处理。

选项:
可能需要恢复数据库。

{Continue} {Back to Segment List}

TYPE2 UNDO

TYPE2 UNDO 是系统管理的 undo 段,它是 rollback 段的一种特殊形式。这些段的坏块需要特殊处理。

选项:
可能需要恢复数据库。

{Continue} {Back to Segment List}

TABLE PARTITION

如果段类型为 TABLE PARTITION,请记录名称和所有者,然后确定哪些分区受到影响:

SELECT partition_name
FROM dba_extents
WHERE file_id = &AFN
AND &BL BETWEEN block_id AND block_id + blocks – 1;
然后按照处理 TABLE 段的步骤继续下面的操作。

选项:
如果所有坏块均位于同一个分区,则此时可以采取的一个做法是用一个空表 EXCHANGE 坏块所在的分区,这可以让应用程序继续运行(无法访问坏块所在的分区中的数据),然后可以从之前的空表中提取任何未损坏的数据。
有关其他选项,请参见下面的 TABLE 选项。

{Continue} {Back to Segment List}

TABLE

如果所有者为“SYS”,则联系 Oracle Support 并上传所有详细信息。
可能需要恢复数据库。

对于非字典 TABLE 或 TABLE PARTITION,确定表中存在哪些索引:

例如: SELECT owner, index_name, index_type
FROM dba_indexes
WHERE table_owner=’&OWNER’
AND table_name=’&SEGMENT_NAME’;
并确定表中是否存在任何主键:

例如:SELECT owner, constraint_name, constraint_type, table_name
FROM dba_constraints
WHERE owner=’&OWNER’
AND table_name=’&SEGMENT_NAME’
AND constraint_type=’P’;
如果存在主键,则确认它是否被任何外键约束引用:

例如:
SELECT owner, constraint_name, constraint_type, table_name
FROM dba_constraints
WHERE r_owner=’&OWNER’
AND r_constraint_name=’&CONSTRAINT_NAME’;
选项:
如果所有者为“SYS”,则联系 Oracle Support 并上传所有详细信息。
可能需要恢复数据库。

对于非字典表,可能的选项包括:
恢复
或 抢救表(或分区)中的数据
然后 重新创建表(或分区)
或 忽略坏块
(例如:使用 DBMS_REPAIR 标记需要跳过的问题块)

{Continue} {Back to Segment List}

IOT(索引组织表)

IOT 表中的坏块应按照表或分区表中的处理方式来处理。
唯一的例外是如果 PK 损坏。
IOT 表的 PK 就是表本身,它不能被删除和重新创建。

选项:
如果所有者为“SYS”,则联系 Oracle Support 并上传所有详细信息。
可能需要恢复数据库。

对于非字典表,可能的选项包括:
恢复
或 抢救表(或分区)中的数据
然后 重新创建表(或分区)
或 忽略坏块
(DBMS_REPAIR 不适用于 IOT)

{Continue} {Back to Segment List}

LOBINDEX

确定 LOB 属于哪个表:

SELECT table_name, column_name
fROM dba_lobs
wHERE owner=’&OWNER’
AND index_name=’&SEGMENT_NAME’;

如果表的所有者为“SYS”,则联系 Oracle Support 并上传所有详细信息。可能需要恢复数据库。

不可以重建 LOB 索引,因此您必须将该问题作为受影响的表中 LOB 列上的坏块来处理。

使用 ”TABLE“ 部分中的 SQL 语句获取包含损坏的 LOB 索引的表的索引和约束信息,然后返回此处。

选项:

如果所有者为“SYS”,则联系 Oracle Support 并上传所有详细信息。
可能需要恢复数据库。

对于非字典表,可能的选项包括:
恢复
或 抢救表(及其 LOB 列)中的数据
然后 重新创建表
忽略坏块的做法通常不可取,除非不大可能对表中的问题列执行任何进一步的 DML 操作。

{Continue} {Back to Segment List}

LOBSEGMENT

确定 LOB 属于哪个表:

例如:
SELECT table_name, column_name
FROM dba_lobs
WHERE owner=’&OWNER’
AND segment_name=’&SEGMENT_NAME’;

如果表的所有者为“SYS”,则联系 Oracle Support 并上传所有详细信息。可能需要恢复数据库。

对于非字典表 …

使用 ”TABLE“ 部分中的 SQL 语句获取包含坏块的 LOB 数据的表的索引和约束信息,然后返回此处查找具体受影响的行的详细信息。

要查找引用损坏的 LOB 块的具体行可能比较困难,因为报告的错误中不会显示表中的哪一行数据包含损坏的 LOB 数据。

Typically one can refer to application logs or any SQL_TRACE or 10046 trace of a session hitting the error (if available) or see if having

event “1578 trace name errorstack level 3”
set in the session helps identify the current SQL/binds/row.

例如:
ALTER SYSTEM SET EVENTS ‘1578 trace name errorstack level 3’;
然后等待应用程序触发该错误,并查找跟踪文件。

如果没有任何线索,您可以构建 PLSQL 块,逐行扫描问题表以提取 LOB 列数据,扫描将一直循环进行,直至发生错误。此方法可能需要一段时间,但它应该可以找到引用了损坏的 LOB 块的数据行的主键或 ROWID。

例如:
set serverout on
exec dbms_output.enable(100000);
declare
error_1578 exception;
pragma exception_init(error_1578,-1578);
n number;
cnt number:=0;
badcnt number:=0;
begin
for cursor_lob in
(select rowid r, &LOB_COLUMN_NAME L from &OWNER..&TABLE_NAME)
loop
begin
n:=dbms_lob.instr(cursor_lob.L,hextoraw(‘AA25889911’),1,999999) ;
exception
when error_1578 then
dbms_output.put_line(‘Got ORA-1578 reading LOB at ‘||cursor_lob.R);
badcnt:=badcnt+1;
end;
cnt:=cnt+1;
end loop;
dbms_output.put_line(‘Scanned ‘||cnt||’ rows – saw ‘||badcnt||’ errors’);
end;
/

another script more generic:

set serverout on
exec dbms_output.enable(100000);
declare
pag number;
len number;
c varchar2(10);
charpp number := 8132/2;

begin
for r in (select rowid rid, dbms_lob.getlength () len
from ) loop
if r.len is not null then
for page in 0..r.len/charpp loop
begin
select dbms_lob.substr (, 1, 1+ (page * charpp))
into c
from
where rowid = r.rid;

exception
when others then
dbms_output.put_line (‘Error on rowid ‘ ||R.rid||’ page ‘||page);
dbms_output.put_line (sqlerrm);
end;
end loop;
end if;
end loop;
end;
/
选项:

如果所有者为“SYS”,则联系 Oracle Support 并上传所有详细信息。
可能需要恢复数据库。

对于非字典表,可能的选项包括:

恢复
或 抢救表(及其 LOB 列)中的数据
然后 重新创建表
或 忽略坏块
(不可以在 LOB 段上使用 DBMS_REPAIR)

{Continue} {Back to Segment List}

TEMPORARY

如果段类型为 TEMPORARY,则坏块不会影响永久对象。检查发生问题的表空间是否正在被用作 TEMPORARY 表空间:

SELECT count(*) FROM dba_users WHERE temporary_tablespace=’&TABLESPACE_NAME’;
选项:

如果是 TEMPORARY_TABLESPACE,则可能可以创建新的临时表空间,并将所有用户切换到该表空间,然后删除有问题的表空间。

如果不是临时表空间,则该块不会再被读取,而且会在下次使用时被重新格式化 — 如果问题的根本原因已经得到解决,则不应再发生该错误。

通常情况下,不需要进行任何还原,但如果磁盘可能有问题,且表空间包含有用数据,则最好对数据库中受影响的文件进行恢复。

{Continue} {Back to Segment List}

其他一些段类型

如果返回的段类型未包含在上述类型中,则请联系 Oracle Support 并提供迄今为止收集的所有信息,以获得相关建议。

{Continue} {Back to Segment List}

“无返回行”

如果没有包含坏块的 extent,则首先再次检查查询中使用的参数。如果您确定文件号和块编号是正确的,且不属于 DBA_EXTENTS 中的某个对象,则执行以下操作:

再次检查相关文件是否为临时文件。
请注意,临时文件的文件号取决于数据库初始化参数 DB_FILES,因此对该参数的任何更改都会改变错误中报告的绝对文件号。
DBA_EXTENTS 不包含本地管理表空间中用于本地空间管理的块。
如果您在数据库运行查询语句的时间点与出错的时间点不相同,那么问题对象可能已经被删除,因此针对 DBA_EXTENTS 的查询可能不会显示任何行。
如果您正在调查的错误由 DBVERIFY 报告,则 DBV 将检查所有块,而不管它们是否属于某个对象。因此,坏块可能存在于数据文件中,但却未被任何对象使用。
选项:

未使用的 Oracle 块上的错误可以忽略,因为如果需要使用该块,Oracle 会创建新的块映像(格式化),因此,该块上的任何问题将永不会被读取。

如果您怀疑该块可能是空间管理块,则可以使用 DBMS_SPACE_ADMIN 包来帮助您进行检查:

exec DBMS_SPACE_ADMIN.TABLESPACE_VERIFY(‘&TABLESPACE_NAME’);
以上命令会将不一致写入跟踪文件,但如果遇到致命的坏块,它将报告如下错误:

ORA-03216: Tablespace/Segment Verification cannot proceed

{Continue} {Back to Segment List}

{go to content}

证据

对于每个坏块,如果需要尝试并确定实际坏块原因,则收集如下物理证据也是一个比较好的方法:

坏块及位于其任意一侧的块的操作系统 HEX 转储。

在 UNIX 上:

dd if=&FILENAME bs=&TS_BLOCK_SIZE skip=&BL-1 count=3 of=BL.dd
^^^^^^^^ ^^^^^^^^^^^^^^ ^^^

例如:对于 BL=1224:

dd if=ts11.dbf bs=4k skip=1223 count=3 of=1223_1225.dd

在 VMS 上:

DUMP/BLOCKS=(start:XXXX,end:YYYY)/out=dump.out &FILENAME

其中 XXXX=操作系统块编号(512 字节块中)
要计算此值,用报告的块编号乘以“&TS_BLOCK_SIZE/512”。
处于 ARCHIVELOG 模式时,复制出错时间前后的归档日志文件的安全副本,最好包括报告错误前数小时的日志文件。并且,保存问题数据文件在出错前的所有副本,因为之前的数据文件映像以及 redo 记录有助于找出错误原因。
(DBV 通常可用于检查问题是否存在于文件的备份副本中)。理想的情况是获得没有报告坏块的数据文件备份映像,以及从该时间点开始到首次报告坏块时间之后不久的时段内的所有 redo 记录。

获得问题块的 Oracle 转储:
ALTER SYSTEM DUMP DATAFILE ‘&FILENAME’ BLOCK &BL;
(DUMP将生成到 USER_DUMP_DEST 下的跟踪文件)。

{Continue} {Back to Segment List}

{go to content}

(5) 选择恢复选项

现在,最佳的恢复选项取决于受影响的对象。前面第 (3) 部分中的说明应该已经重点介绍了针对每个受影响对象的主要可用选项。选择的实际恢复方法可能包含以下一种或多种混合方法:

是否需要进行任何恢复操作?

表空间中,或位于不再属于任何数据库对象的块中,则无需进行任何操作,尽管将问题表空间重定位到其他存储设备中可能较为明智。

请参阅警告

可以使用完全恢复吗?

要选用完全恢复,必须满足如下条件:

数据库处于 ARCHIVELOG 模式
(“ARCHIVE LOG LIST”命令显示 Archivelog 模式)

拥有受影响文件的完好备份。请注意,在某些情况下,坏块可能已经存在,但在很长一段时间内未被发现。如果最近的数据文件备份仍包含坏块,那么只要您拥有所 有必需的归档日志,就可以尝试使用更早的备份。
(通常可以使用 DBV START= / END= 选项来检查位于某个备份文件的恢复副本中的特定块是否损坏)

从备份时间开始到当前时间点的所有归档日志均可用

当前的在线日志均可用且完好无缺

错误不是由运行 NOLOGGING 操作之后执行的恢复所导致的

如果满足上述条件,完全恢复通常是首选方法

*但请注意*

如果事务回滚已发现坏块位于对象上,而非 rollback 段本身,则 undo 操作可能已被放弃。在这种情况下,可能需要在恢复完成后重建索引/检查数据完整性。

如果要恢复的文件包含自上次备份以来执行的 NOLOGGING 操作的数据,在使用了数据文件或数据库恢复的情况下,这些块将被标记为“坏块”。在某些情况下,这会使情况更加糟糕。
如果执行数据库恢复后坏块仍然存在,则表示所有备份都包含坏块,底层错误仍存在,或问题通过 redo 重现。在这些情况下,需要选择其他一些恢复选项。

请参阅 “(4A) 完全恢复” ,以了解完全恢复步骤。

{go to content}

如果不需要从对象本身提取任何数据,能否删除或重新创建该对象?

您可以删除对象或从脚本/最近导出的副本重新创建对象。一旦删除一个对象后,该对象中的块将被标记为“空闲”,并且该块在被分配到新对象时将被重新格式化。明智的做法是,对表进行重命名,而不是删除,除非您完全确定不再需要其中的数据。

对于表分区,只需要删除受影响的分区。

例如: ALTER TABLE … DROP PARTITION …
如果坏块影响到分区段头,或者包含分区头的文件处于离线状态,则 DROP PARTITION 可能会失败。在这种情况下,首先将其更换为具有相同定义的表,之后仍然可以删除该分区。

例如: ALTER TABLE .. EXCHANGE PARTITION .. WITH TABLE ..;
最常见的可重建对象为索引。始终在处理表中的索引问题之前处理表坏块。
有关详细信息,请参阅”(4B) 重建索引” 。

对于任何段,如果您拥有坏块的绝对文件号和块号,则可使用以下快速提取对象 DDL 的方法:

set long 64000
select dbms_metadata.get_ddl(segment_type, segment_name, owner)
FROM dba_extents
WHERE file_id=&AFN
AND &BL BETWEEN block_id AND block_id + blocks -1;

{go to content}

是否需要在重新创建对象之前抢救数据?

如果问题位于定期%9