对oracle中出现的坏块的处理方法

这篇文章介绍在oracle数据文件中出现一个或多个数据块坏块时的处理方法.当出现数据块坏块出误时对于每一个坏块都提供了以下信息:
1.包含这个坏块的数据文件的绝对文件号可以标示为”AFN”.
2.包含这个坏块的数据文件的文件名可以标示为”FILENAME”(如果知道文件号但不知道文件名那么可以执行select name from v$datafile where file#=&AFN来得到文件名,如果文件号在v$datafile中没有记录且AFN比参数db_files参数的值还大那么这个文件可能是临时文件.如果是这种情况可以执行select name from v$tempfile where file#=(&AFN-&DB_FILES_value)
3.数据文件中坏块的块号可以标示为”BL”
4.受坏块影响的表空间号和表空间名称可以标示为”TSN”和”TABLESPACE_NAME”.可以执行select ts# “TSN” from v$datafile where file#=&AFN;select tablespace_name from dba_data_files where file_id=&AFN来查询.
5.出现坏块的表空间的数据块大小可以标示为”TS_BLOCK_SIZE”.对于oracle9i来说可以执行select block_size from dba_tablespace where tablespace_name=(select tablespace_name from dba_data_files where file_id=&AFN);来查询数据块大小.对于oracle7.8.0和8.1在数据库中每一个表空间都有相同的数据块大小.对于这些版本可以使用show parameter db_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,相对文件号RFN是7,数据块BL是12698,文件名FILENAME是/oracle1/oradata/V816/oradata/V816/users01.dbf,表空间号和表空间名可以用上面的查询得到.

处理坏块的步骤
导致坏块的原因有许多种例如:
坏的 IO 硬件/固件
OS 问题
Oracle 问题
对于执行过“UNRECOVERABLE”或“NOLOGGING”操作的数据库进行恢复在这种情况下可能产生 ORA-1578 错误

在遇到坏块时,我们通常无从了解根本原因,并且在大多数情况下,当前最迫切的是重新启动数据库并使其运行起来.
1. 确定坏块问题的范围,并确定这些问题是持久性问题还是暂时性问题
如果问题涉及范围很大,或错误不稳定,则关键在于先识别原因(检查硬件等).这点很重要.因为如果是底层硬件出现错误.恢复系统便毫无意义

2.更换或拆下任何有问题的或可疑的硬件

3.确定受到影响的数据库对象有哪些

4.选择最合适的数据库恢复/数据抢救选项

确定坏块问题的范围
每次发生坏块错误时,都应记下完整的错误消息,并查看该实例的告警日志和跟踪文件,以了解任何相关的错误.首先进行这些步骤非常重要,这可以评估该损坏是单个块,还是由于UNRECOVERABLE操作产生的错误,或是更严重的问题.

使用DBVERIFY扫描受影响的文件以及一切重要的文件也是不错的办法,这样可以检查是否有其他坏块,从而确定问题的范围.一旦确定了损坏的文件/块组合列表,即可使用以下步骤来帮助确定应采取何种措施:
1.完整记录初始错误,以及发生错误的应用程序的详细信息
2.及时地保存从告警日志中首次 (FIRST) 记录到问题前数小时到当前时间点所提取的内容
3.保存告警日志中提到的任何跟踪文件
4.记录最近遇到的任何 OS 问题
5.记录是否正在使用任何特殊功能,例如:ASYNC IO、快速写入磁盘选项等
6.记录当前的备份位置(日期、类型等)
7.记录数据库是否处于ARCHIVELOG 模式,例如:在SQL*Plus(或 Server Manager)中运行“ARCHIVE LOG LIST”

更换或拆下可疑硬件
大多数坏块问题是由故障硬件导致的.如果出现硬件错误或可疑组件,最好进行修复,或者在执行恢复操作之前,确保在单独的磁盘子系统上有足够的可用空间用于恢复,您可以使用以下步骤移动数据文件:
1.确保要迁移的文件已离线或数据库实例处于 MOUNT 状态(未打开)
2. 将该数据文件物理还原(或复制)到新位置 例如:/newlocation/myfile.dbf
3.将该文件的新位置告知 Oracle.
例如:ALTER DATABASE RENAME FILE ‘/oldlocation/myfile.dbf’ TO ‘/newlocation/myfile.dbf’;
(请注意,您不能对临时文件进行重命名,而应删除临时文件并在新位置重新创建)
4.使相关数据文件/表空间上线(如果数据库已打开)

注意:
如果存在多个错误(不是由于 NOLOGGING操作导致的)或受影响文件所在的OS层面出现错误或错误是暂时性的且游离不定,那么,如果不解决底层问题或准备另外的磁盘空间,那么进行任何操作都是毫无意义的.

如果使用了任何特殊IO选项,例如direct IO,async IO或类似的选项,最好将其禁用,以消除这些选项成为潜在问题原因的可能性

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

对于每个坏块,请收集下表中的信息.进行此操作的步骤如下所述。
1.初始错误
2.绝对文件号AFN
3.相关文件号RFN
4.块编号BL
5.表空间
6.段类型
7.段所有者.名称
8.相关对象
9.恢复选项

在Oracle8/8i/9i/10g中;绝对文件号和相关文件号通常是一样的,但也可能不同(尤其是在数据库是由Oracle7迁移而来的情况下).要获得正确的AFN和RFN编号,否则您可能最终抢救的是错误的对象.

下列查询将显示数据库中数据文件的绝对和相关文件号:
SELECT tablespace_name, file_id “AFN”, relative_fno “RFN” FROM dba_data_files;

在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”和块编号“&BL”的情况下,下列查询将显示对象的段类型,所有者和名称,数据库必须打开才能使用此查询:
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;

按段类型分类的“相关对象”和可能的“恢复选项”:
相关对象和能够使用的恢复选项取决于SEGMENT_TYPE.对于各种最常见的段类型,其他查询和可能的恢复选项如下所示:
CACHE
如果段类型为 CACHE,请再次检查您是否输入了正确的 SQL语句 和参数。
恢复选项:可能需要恢复数据库。

CLUSTER
如果段类型为 CLUSTER,则应确定它包含哪些表。
例如:
SELECT owner, table_name
FROM dba_tables
WHERE owner=’&OWNER’
AND cluster_name=’&SEGMENT_NAME’;

恢复选项:
如果所有者为“SYS”可能需要恢复数据库。

对于非数据字典cluster,可能的选项包括:
恢复或 抢救cluster中所有表的数据,然后重新创建cluster及其所有表,
cluster可能包含多个表,因此在做出决策之前,最好先收集cluster中每个表的信息。

INDEX PARTITION
如果段类型为INDEX PARTITION,请记录名称和所有者,然后确定哪些分区受到影响:
SELECT partition_name
FROM dba_extents
WHERE file_id = &AFN
AND &BL BETWEEN block_id AND block_id + blocks – 1;
然后按照处理INDEX段的步骤继续下面的操作.
恢复选项:
使用下列语句可以重建索引分区:
ALTER INDEX xxx REBUILD PARTITION ppp;

INDEX
如果段类型为INDEX,对于非字典INDEX或INDEX PARTITION,确定索引位于哪个表中:
例如:
SELECT table_owner, table_name
FROM dba_indexes
WHERE owner=’&OWNER’
AND index_name=’&SEGMENT_NAME’;
并确定索引是否支持约束:
例如:
SELECT owner, constraint_name, constraint_type, table_name
FROM dba_constraints
WHERE owner=’&TABLE_OWNER’
AND constraint_name=’&INDEX_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”,可能需要恢复数据库。
对于非字典索引,可能的选项包括:
恢复或 重建索引(任何相关联的约束会随之禁用/启用)

ROLLBACK
如果段类型为ROLLBACK,因为 ROLLBACK 段坏块需要特殊处理。
选项可能需要恢复数据库。

TYPE2 UNDO
TYPE2 UNDO 是系统管理的undo段,它是 rollback段的一种特殊形式.这些段的坏块需要特殊处理.
选项可能需要恢复数据库。

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
如果所有者为“SYS”,可能需要恢复数据库。
对于非字典 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”,可能需要恢复数据库。
对于非字典表,可能的选项包括:
恢复或 抢救表(或分区)中的数据,然后重新创建表(或分区)或忽略坏块(例如:使用DBMS_REPAIR标记需要跳过的问题块)

IOT(索引组织表)
IOT 表中的坏块应按照表或分区表中的处理方式来处理。
唯一的例外是如果 PK 损坏。
IOT表的PK就是表本身它不能被删除和重新创建
选项:
如果所有者为“SYS”,可能需要恢复数据库。
对于非字典表,可能的选项包括:
恢复或 抢救表(或分区)中的数据,然后重新创建表(或分区)或忽略坏块(DBMS_REPAIR不适用于IOT)

LOBINDEX
确定LOB属于哪个表:
SELECT table_name, column_name
FROM dba_lobs
WHERE owner=’&OWNER’ AND index_name=’&SEGMENT_NAME’;
如果表的所有者为“SYS”可能需要恢复数据库。
不可以重建 LOB 索引,因此您必须将该问题作为受影响的表中LOB列上的坏块来处理。
选项:
如果所有者为“SYS”可能需要恢复数据库。
对于非字典表,可能的选项包括:
恢复或 抢救表(及其 LOB 列)中的数据,然后重新创建表,忽略坏块的做法通常不可取,除非不大可能对表中的问题列执行任何进一步的 DML 操作。

LOBSEGMENT
确定 LOB 属于哪个表:
例如:
SELECT table_name, column_name
FROM dba_lobs
WHERE owner=’&OWNER’
AND segment_name=’&SEGMENT_NAME’;
如果表的所有者为“SYS”,可能需要恢复数据库。
对于非字典表,要查找引用损坏的 LOB 块的具体行可能比较困难,因为报告的错误中不会显示表中的哪一行数据包含损坏的 LOB 数据。
通常可以参考发生该错误的应用程序日志、任何SQL_TRACE、会话的10046 跟踪文件(如果有),或通过在会话中设置事件“1578 trace name errorstack level 3”,查看是否有助于标识当前的 SQL/绑定/行。
例如:
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;
/
损坏的 LOB 块可能仅显示为旧版本(为保证一致性读取),且该块未被重新使用,在这种情况下,所有表中所有行都可以访问,但一旦该块被回收重新使用,就不可以插入/更新 LOB 列了。
选项:
如果所有者为“SYS”,可能需要恢复数据库。
对于非字典表,可能的选项包括:
恢复或抢救表(及其 LOB 列)中的数据,然后重新创建表或忽略坏块(不可以在 LOB 段上使用 DBMS_REPAIR)

TEMPORARY
如果段类型为TEMPORARY,则坏块不会影响永久对象.检查发生问题的表空间是否正在被用作TEMPORARY表空间:
SELECT count(*) FROM dba_users
WHERE temporary_tablespace=’&TABLESPACE_NAME’;
选项:
如果是 TEMPORARY_TABLESPACE,则可能可以创建新的临时表空间,并将所有用户切换到该表空间,然后删除有问题的表空间。
如果不是临时表空间,则该块不会再被读取,而且会在下次使用时被重新格式化 — 如果问题的根本原因已经得到解决,则不应再发生该错误。
通常情况下,不需要进行任何还原,但如果磁盘可能有问题,且表空间包含有用数据,则最好对数据库中受影响的文件进行恢复

“无返回行”
如果没有包含坏块的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
位图空间管理块上发生的错误通常可以通过运行以下命令来修正:
exec DBMS_SPACE_ADMIN.TABLESPACE_REBUILD_BITMAPS(‘&TABLESPACE_NAME’);
对于每个坏块,如果需要尝试并确定实际坏块原因,则收集如下物理证据也是一个比较好的方法:
i) 坏块及位于其任意一侧的块的操作系统 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 上:
其中 XXXX=操作系统块编号(512 字节块中)
要计算此值,用报告的块编号乘以“&TS_BLOCK_SIZE/512”。

ii) 处于 ARCHIVELOG 模式时,复制出错时间前后的归档日志文件的安全副本,最好包括报告错误前数小时的日志文件。并且,保存问题数据文件在出错前的所有副本,因为之前的数据文件映像以及 redo 记录有助于找出错误原因DBV 通常可用于检查问题是否存在于文件的备份副本中).理想的情况是获得没有报告坏块的数据文件备份映像,以及从该时间点开始到首次报告坏块时间之后不久的时段内的所有 redo 记录。

iii) 获得问题块的 Oracle 转储:
ALTER SYSTEM DUMP DATAFILE ‘&FILENAME’ BLOCK &BL;

(4) 选择恢复选项

现在,最佳的恢复选项取决于受影响的对象。前面第 (3) 部分中的说明应该已经重点介绍了针对每个受影响对象的主要可用选项。选择的实际恢复方法可能包含以下一种或多种混合方法:
是否需要进行任何恢复操作?
如果错误发生在TEMPORARY 表空间中,或位于不再属于任何数据库对象的块中,则无需进行任何操作.

可以使用完全恢复吗?
要选用完全恢复,必须满足如下条件:
数据库处于 ARCHIVELOG 模式(“ARCHIVE LOG LIST”命令显示 Archivelog模式)

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

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

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

错误不是由运行NOLOGGING 操作之后执行的恢复所导致的
如果满足上述条件,完全恢复通常是首选方法
但请注意:
(a) 如果事务回滚已发现坏块位于对象上,而非 rollback 段本身,则 undo 操作可能已被放弃。在这种情况下,可能需要在恢复完成后重建索引/检查数据完整性。

(b) 如果要恢复的文件包含自上次备份以来执行的 NOLOGGING 操作的数据,在使用了数据文件或数据库恢复的情况下,这些块将被标记为“坏块”。在某些情况下,这会使情况更加糟糕。

如果执行数据库恢复后坏块仍然存在,则表示所有备份都包含坏块,底层错误仍存在,或问题通过redo 重现。在这些情况下,需要选择其他一些恢复选项。

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

对于表分区,只需要删除受影响的分区。例如:ALTER TABLE …DROP PARTITION …

如果坏块影响到分区段头,或者包含分区头的文件处于离线状态,则 DROP PARTITION 可能会失败。在这种情况下,首先将其更换为具有相同定义的表,之后仍然可以删除该分区。
例如:ALTER TABLE ..EXCHANGE PARTITION ..WITH TABLE ..;
最常见的可重建对象为索引。始终在处理表中的索引问题之前处理表坏块

对于任何段,如果您拥有坏块的绝对文件号和块号,则可使用以下快速提取对象 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;

是否需要在重新创建对象之前抢救数据?
如果问题位于定期更新的关键应用表上,则可能需要尽可能多地抢救表中数据,然后重新创建该表。

当前忽略坏块是否可取?
在某些情况下,最直接的选项可能就是忽略坏块,并阻止应用程序对它进行访问。

最后的选项
将数据库或表空间恢复到较早的时间点(通过时间点恢复)或还原出现坏块前的冷备份或使用现有导出文件

完全恢复
如果数据库处于ARCHIVELOG 模式下,且拥有受影响文件的完好备份,则恢复通常为首选方法.这不保证可以解决问题,但的确可以有效的解决大部分坏块问题.如果恢复再次引发问题,则返回到以上选项列表并选择其他方法.

如果使用的是Oracle9i(或更高版本),则可以使用RMAN BLOCKRECOVER命令执行块级恢复。

如果使用的是较早版本的Oracle,则可以执行数据文件恢复(数据库其他部分可以继续运行),或数据库恢复(需要关闭数据库)

如果使用的是Oracle 11g(或更高版本,则可以使用“Data Recovery Advisor(数据恢复指导)”.

块级恢复
自Oracle9i版本起,RMAN允许恢复单个块,同时数据库的其他部分(包括数据文件中的其他块)仍可以进行正常访问.请注意,块级恢复只能将块完全恢复到当前时间点.要使用此选项恢复单个块,不一定要使用 RMAN 进行备份.
例如:
实际情况是,文件6的块30上发生ORA-1578错误,可能是由于介质问题导致的坏块,且您拥有该文件的完好冷备份映像,并已还原到“…/RESTORE/filename.dbf”.假设所有归档日志均存在(位于默认位置),则可以通过RMAN使用以下命令序列执行块级恢复:
rman nocatalog
connect target
catalog datafilecopy ‘…/RESTORE/filename.dbf’;
run {blockrecover datafile 6 block 30;};
此操作将使用注册的数据文件备份映像和任何需要的归档日志来执行块恢复,仅将有问题的块恢复到当前时间点.

数据文件恢复
数据文件恢复包括下列步骤.如果有多个文件,则针对每个文件重复执行这些步骤,或参阅下面的“数据库恢复”.当数据库处于 OPEN 或 MOUNTED 状态时,均可使用这些步骤.
使受影响的数据文件离线
例如:ALTER DATABASE DATAFILE ‘name_of_file’ OFFLINE;

将文件复制到安全位置(以防备份损坏)

将文件的最新备份还原到完好的磁盘上

使用DBVERIFY检查还原的文件是否有坏块

假设还原的文件完好,则将数据文件重命名并保存到新位置(如果不是原来的位置)
例如:ALTER DATABASE RENAME FILE ‘old_name’ TO ‘new_name’;

恢复数据文件
例如:RECOVER DATAFILE ‘name_of_file’;

使数据文件上线
例如:ALTER DATABASE DATAFILE ‘name_of_file’ ONLINE;

数据库恢复
数据库恢复通常包含以下步骤:
关闭数据库(使用选项 immediate 或 abort)

将待恢复的所有文件的当前副本复制到安全位置

将备份文件还原到完好的磁盘上

请勿还原控制文件或在线REDO 日志文件

使用DBVERIFY检查还原的文件

启动数据库到MOUNT状态(startup mount)

对任何需要重新定位的数据文件进行重命名
例如:ALTER DATABASE RENAME FILE ‘old_name’ TO ‘new_name’;

确保所有必需的文件在线
例如:ALTER DATABASE DATAFILE ‘name_of_file’ ONLINE;

恢复数据库
例如:RECOVER DATABASE

打开数据库
例如:ALTER DATABASE OPEN;

一旦执行了完全恢复,最好在允许使用之前先检查数据库:
针对每个问题对象运行“ANALYZE VALIDATE STRUCTURE CASCADE”,检查表/索引是否存在不匹配。如果有任何 und 操作曾被放弃,此命令可能会显示不匹配,此时需要重建索引。

在应用程序级别检查表中数据的逻辑完整性。

重建索引
损坏对象为用户索引时,如果底层表没有损坏,则可以删除并重建该索引。

如果底层表也已经损坏,则应在重建任何索引之前先解决该表的坏块。

如果收集的信息表示索引有从属外键约束,则需要执行以下操作:
ALTER TABLE DISABLE CONSTRAINT ;

使用以下命令重建主键
ALTER TABLE

DISABLE CONSTRAINT ;
DROP INDEX ;
CREATE INDEX
.. with appropriate storage clause
ALTER TABLE

ENABLE CONSTRAINT ;

启用外键约束
ALTER TABLE ENABLE CONSTRAINT ;

对于索引分区,以执行以下命令:
ALTER INDEX …REBUILD PARTITION …;

注意:
(1) 不要使用“ALTER INDEX .. REBUILD”命令重建损坏的非分区索引,这一点非常重要,因为此操作通常会尝试从包含坏块的现有索引段中构建新索引..“ALTER TABLE … REBUILD ONLINE”和“ALTER INDEX … REBUILD PARTITION …”不会从旧索引段中构建新索引,因此可以使用。

(2) 如果新索引包含的列为现有索引的子集,则 Create INDEX 可以使用现有索引中的数据,因此,如果您有两个损坏的索引,应在重建之前将两个都删除。

(3) 重建索引时,请确保使用正确的存储选项。

抢救表中数据
如果损坏的对象为TABLE 或 CLUSTER 或 LOBSEGMENT,则必须明白,坏块内的数据已经丢失.部分数据可能可以从块的HEX转储中,或从索引涵盖的列中抢救回来.

由于可能需要从索引中抢救坏块中的数据,因此最好不要删除任何现有索引,直至所有需要的数据提取完成。

从包含坏块的表中提取数据有多种方法。选择最恰当的方法,详细信息如下所述.这些方法的目的是从可访问的表块中提取尽可能多的数据.通常,将损坏的表重命名是一个比较好的方法,这样就可以使用正确的名称创建新对象.
例如:RENAME TO ;

从坏块表中提取坏块周围数据的方法
(1) 从Oracle 7.2开始(包括 Oracle 8.0、8.1 和 9i)可以跳过表中的坏块。
这是到目前为止最简单的提取表数据的方法,用DBMS_REPAIR.SKIP_CORRUPT_BLOCKS or Event 10231

如果坏块位于IOT overflow 段,则应使用相同的方法,不同的是使用Event 10233和全索引扫描

请注意,此方法只适用于块的“包装”已被标记为“坏块”的情况。例如:如果块报告 ORA-1578 错误。如果问题为 ORA-600 或其他非ORA-1578 错误,则通常可以使用 DBMS_REPAIR 将表中坏块标记为“软坏块”。这样在您访问该数据块时,系统将显示 ORA-1578错误,从而可以使用 DBMS_REPAIR.SKIP_CORRUPT_BLOCKS。

注意:被“FIX_CORRUPT_BLOCKS”程序标记为“坏块”的块在任何还原/恢复操作之后还将被标记为“坏块”.

使用DBMS_REPAIR进行此操作概括起来步骤如下:
使用DBMS_REPAIR.ADMIN_TABLES 创建管理表

使用DBMS_REPAIR.CHECK_OBJECT 找到问题块

在损坏问题块之前将其中所有完好的数据导出。

使用DBMS_REPAIR.FIX_CORRUPT_BLOCKS将找到的问题块标记为“坏块”,然后它们就会显示 ORA-1578

如果需要,使用 DBMS_REPAIR.SKIP_CORRUPT_BLOCKS跳过表中的坏块。

(2) 从 Oracle 7.1 开始,可以使用 ROWID 范围扫描.此功能的语法较为复杂,但可以使用 ROWID提示选择坏块周围的数据.

(3) 如果存在主键,则可以通过此索引选择表数据。也可以通过任何其他索引选择一些数据。此方法较慢,花费时间较长,通常只有 Oracle 7.0 版本才使用

(4) 有多种抢救程序/PLSQL 脚本可用于抢救表中的数据。与上述方法相比,这些方法在设置和使用方面需要花费更长的时间,但常常能够处理除 ORA-1578 之外的各类坏块

从包含损坏的LOBSEGMENT 块的表中提取数据的方法:
在 LOB 段上不可以使用 DBMS_REPAIR,如果坏块 LOB 块未被表中的任何行引用,则应该可以使用 CREATE TABLE as SELECT (CTAS)来按选择创建表,或按原样导出/删除/导入该表。

如果坏块LOB 块被某个行引用,则应该可以使用不包括问题行的WHERE谓词进行选择或导出

注意:可以将问题行的LOB列值更新为NULL,从而使SELECT操作不再返回ORA-1578错误,但是坏块将等待被重新使用,随着对行中的 LOB列进行INSERT或UPDATE操作,当有问题的块被重新使用时,最后还是会报ORA-1578错误,那时的情况比已知行出现坏块更糟糕.因此,只有您打算立刻重新创建表,才应该将LOB列设为NULL.

从坏块本身提取数据
由于坏块本身已经“损坏”,则从该块中提取的任何数据都应被视为可疑数据,从坏块本身获取数据行的主要方法包括:
对于 TABLE 的块,Oracle Support 可以使用一款尝试解释块内容的工具。

使用表中现有索引,利用落在坏块内的ROWID 来提取索引所涵盖的列数据,上文提到的 ROWID 范围扫描文章在接近结束时对此内容有所介绍:
对于 Oracle8/8i,请参阅 Document 61685.1
对于 Oracle7,请参阅 Document 34371.1

在 redo 流上可以使用 LogMiner 来查找向问题块加载数据的初始插入/更新操作。此处的主要因素是数据实际被放入问题块的时间.例如,行2可能在昨天已插入,而行1可能在1年前已插入.

忽略坏块
出错时可以忽略坏块并接受报告的错误,或在应用程序级别阻止对出问题的块行进行访问。
例如:如果问题块/行位于子表中,则可以在应用程序级别阻止对父表中对应行的访问,从而子行就永不会被访问(但要注意级联类约束)

这样做可能不利于批量访问数据的报告和其他任务,因此,为了阻止块在被访问时报错,前面所述的DBMS_REPAIR选项也不失为一个可取的方法.使用这种方法标记并跳过坏块提供了一种短期的解决方案.从而在计划停机时可以尝试进行完全数据抢救和/或恢复,或留出更多时间在第二个(克隆)数据库上尝试其他恢复选项.但请注意,使用DBMS_REPAIR.FIX_CORRUPT_BLOCKS标记块坏块将导致标记的块在恢复后还是“坏块”。

忽略坏块对于快速老化且即将被清除的数据而言是比较好的选择(例如,在按日期分区的表中,较老的分区将在某时间点被删除).

忽略LOB段上的坏块
在应用程序级别,可以忽略损坏的LOB列,直到可以重新构建该表.确保不出现上述“警告”中的情形的一种方法是确保应用程序只能通过表上的包含WHERE 谓词的视图来访分表中的数据.
例如:假设表 MYTAB(a number primary key,b clob)有一行或多行指向损坏的 LOB 数据。
ALTER TABLE MYTAB ADD ( BAD VARCHAR2(1) );

CREATE VIEW MYVIEW AS SELECT a,b FROM MYTAB WHERE BAD is null;

对任何问题行设置 BAD=’Y’

如果只通 MYVIEW 访问 MYTAB,该行将永不可见,因此也无法更新,从而实现了坏块条目隔离,直到问题解决.

很明显,此示例更多的是一个设计时解决方案,但某些应用程序可能已有类似机制,且可能只通过某个视图(或通过 RLS 策略)访问数据,从而提供某些选项来隐藏问题行。

针对忽略坏块的警告
虽然可以忽略坏块,但需要注意的是,坏块在运行DBVERIFY,RMAN 备份时仍然会以警告/错误等形式出现。请务必仔细记录您将在这些工具中看到的任何坏块,尤其是您期望在使用RMAN时跳过的任何块(例如,设置了 MAX_CORRUPT),并确保在清除坏块后移除任何对错误的“接受”选项.
例如:假设坏块已处理为忽略坏块,并在应用程序级别跳过问题行。RMAN可能被配置为在备份时接受坏块。然后在稍后的表重组期间重新创建表。如果 RMAN 配置未及时更新以反映目前已无任何错误,则 RMAN 可能会忽略稍后出现的某些其他坏块。

此外,还有重要的一点需要注意,忽略table段中的坏块可能导致查询返回不一致的结果。
例如:设置了 SKIP_CORRUPT 的表可能出现不同的结果,具体取决于是使用了了索引扫描还是表访问,其他报告可能只是报错.。

请注意,如果忽略坏块但使用DBMS_REPAIR.FIX_CORRUPT_BLOCKS标记,系统会向坏块中写入redo信息,这可能会限制后续的恢复选项.

最后的选项
如果你有standby环境(物理或逻辑),请首先对其进行检查。

无论问题发生在何种类型的块上,均可使用一种可能的选项,即将数据库或问题表空间恢复到出现坏块之前的某个时间点.此选项的困难之处在于,并不总能知道问题首次出现的时间.

DBVERIFY通常可用于检查还原的文件是否存在坏块.尤其是,START= / END= DBV选项可用于在还原的备份映像上快速进行首次测试,以检查问题块本身是否出错。

下面列出了一些可用于进行恢复操作的最终选项,当出现其中一种或多种情况:
您丢失了非常重要的数据文件(或数据文件出现坏块),而没有问题文件的正常备份(无坏块)
既不处于ARCHIVELOG 模式,也没有自文件创建以来的全部归档日志
完全恢复后仍重复出现问题

最后的机会:
请注意,如果丢失了数据文件的所有副本,但仍具有自文件创建以来的全部归档日志,则仍有可能恢复该文件。
例如:
ALTER DATABASE CREATE DATAFILE ‘….'[as ‘…’] ;

RECOVER DATAFILE ‘….’

ALTER DATABASE DATAFILE ‘….’ONLINE;
如果您遇到这种情况,请在继续下面的操作之前先尝试使用这些步骤来恢复数据文件。

如果您到达这一步,就说明没有其他办法可以将文件恢复到当前时间点.此时最好关闭实例,并对当前数据库进行备份,以便在选用的措施失败后仍然能够回退到当前时间点.(例如:如果发现备份坏块).

可用的一些选项概述如下:
恢复到早期的冷备份
例如:如果处于 NOARCHIVELOG 模式
从冷备份建立克隆数据库
并提取(导出)问题表
或传输问题表空间

使用基于时间点的恢复将数据库恢复到一致的时间点
需要完好备份和任何所需的归档日志
必须还原所有文件且将整个数据库前滚到恰当的时间点。
可以在克隆数据库中执行基于时间点的恢复,然后将问题表空间传输到问题数据库,或将问题表利用导出/导入工具从克隆数据库导入到问题数据库.

表空间基于时间点的恢复
可以仅对受影响的表空间执行基于时间点的恢复.

从逻辑导出/副本重新创建数据库
需要具有完好的数据库逻辑备份
注意:要使用此选项,必须重新创建数据库。
与其他选项一样,可以在克隆数据库中进行重新创建,只为获得问题表的完好映像.

总之做好备份是DBA最重要的工作.

发表评论

电子邮件地址不会被公开。