【转】如何格式化不属于任何段的损坏块
d1. Rman 备份失败,显示 ORA-19566 错误,且被报告的坏块不属于任何对象 2. Dbverify 显示存在坏块 3. 坏块不属于任何对象 CAUSE 在重新使用和重新格式化坏块之前,RMAN 和 DBV 仍会一直报告坏块。 SOLUTION 下面提供一种可以解决该问题的方式。请注意,我们并不保证这一方式适用,但它曾被多次用于解决该问题。此外,如果某一特定数据文件中坏块数量很多,请在第 6 步中出现块编号提示时,输 入该数据文件中坏块的最高块编号。 如果坏块位于数据文件的可用空间中,Oracle 将自动对该块进行重新格式化并重新使用。 在本文档中,我们尝试手动重新格式化坏块。 第 1 步 - 确定损坏的数据文件 查看 ORA-19566 消息,确定损坏的数据文件。 示例: RMAN-03009: failure of backup command on nm4501 channel at 04/29/2005 09:44:41 ORA-19566: exceeded limit of 0 corrupt blocks for file E:\xxxx\test.ORA. 坏块位于文件 E:\xxxx\test.ORA 中。 第 2 步 - 在受影响的数据文件上运行 DBV/Rman 验证并检查坏块 在报告坏块的数据文件上运行 dbverify。 示例输出: DBVERIFY: Release 9.2.0.3.0 - Production on Thu Aug 25 11:15:54 2005 Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved. DBVERIFY - Verification starting : FILE = E:\xxxx\test.ORA Page 48740 is marked corrupt *** Corrupt block relative dba: 0x01c0be64 (file 7, block 48740) Bad check value found during dbv: Data in bad block - type: 0 format: 2 rdba: 0x0000be64 last change scn: 0x0000.00000000 seq: 0x1 flg: 0x05 consistency value in tail: 0x00000001 check value in block header: 0xb964, computed block checksum: 0x2a5a spare1: 0x0, spare2: 0x0, spare3: 0x0 DBVERIFY - Verification complete Total Pages Examined : 64000 Total Pages Processed (Data) : 0 Total Pages Failing (Data) : 0 Total Pages Processed (Index): 1751 Total Pages Failing (Index): 0 Total Pages Processed (Other): 45 Total Pages Processed (Seg) : 0 Total Pages Failing (Seg) : 0 Total Pages Empty : 62203 Total Pages Marked Corrupt : 1 请注意,在数据文件 7 中,报告 块 48740 损坏。 或者 对于整个数据库 Rman> backup validate check logical database ; For specific datafile Rman> backup validate check logical datafile <fileno> ; Once done query SQL>Select * from v$database_block_corruption ; **如果在第 2 步中 v$database_block_corruption 报告的块数量很多,接下来最好使用第 4 步而不是第 3 步。 第 3 步 - 检查块是否属于任何对象 查询 dba_extents,确认坏块是否属于任何对象。 SQL> select segment_name, segment_type, owner from dba_extents where file_id = <Absolute file number> and <corrupted block number> between block_id and block_id + blocks -1; 如果块不属于任何对象,查询dba_free_space 确认坏块是否属于数据文件的可用空间。 SQL> Select * from dba_free_space where file_id= <Absolute file number> and <corrupted block number> between block_id and block_id + blocks -1; 第 4 步 - 查找受影响的块并验证其是否属于任何段的一种比较好的方法是使用 RMAN,这种方法既好用又便捷。 如果在第 2 步中已经运行了 rman 验证,请直接转到下面给出的 sqlplus 脚本,以确认对象。 $ rman target / nocatalog or $ rman target sys/ nocatalog run { allocate channel d1 type disk; allocate channel d2 type disk; ..................................................................... ... multiple channels may be allocated for parallelizing purposes ... ... depends: RMAN - Min ( MAXOPENFILES , FILESPERSET ) ... ... ... ... Defaults: MAXOPENFILES =8, FILESPERSET =64 ... ... ... ..................................................................... allocate channel dn type disk; backup check logical validate database; release channel d1; release channel d2; ...................................... ... release all channels allocated ... ...................................... release channel dn; } 重要说明:- 如果数据库处于 NOARCHIVELOG 模式,那么必须在数据库正常关闭之后的装载阶段运行上述 RMAN 命令。 否则将输出错误 RMAN-03009: failure of backup command on d1 channel at 12/07/2009 18:55:25 ORA-19602: cannot backup or copy active file in NOARCHIVELOG mode 此限制已在 11g 中解除。 *** 在进行进一步操作之前,*必须*运行并完成 RMAN 命令“backup check logical validate database”。 *** 在进行进一步操作之前,*必须*运行并完成 RMAN 命令“backup check logical validate database”。 *** 此命令完成(基于文件)后将会填充“v$database_block_corruption”视图。 *** 如果未完成,在接下来的步骤中您就有可能得到无效/不完整的信息。 运行以下 sql 查询,以确定块是位于可用空间中还是已占用空间中 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#; 第 5 步 - 以非 SYS 或 SYSTEM(用户)的用户身份创建一个虚拟表 SQL> connect scott/password 在包含出现坏块的数据文件的表空间中创建虚拟表,并使用 nologging 选项,以防止生成 redo记录: SQL> create table s ( n number, c varchar2(4000) ) nologging tablespace <tablespace name having the corrupt block> ; 可以根据具体环境的不同使用不同的存储参数。 通过查询 user_segments,确定在正确的表空间中创建了表: SQL> select segment_name,tablespace_name from user_segments where segment_name='S' ; 第 6 步 - 在虚拟表上创建触发器,一旦重新使用坏块,该触发器便会引发异常 以 sys 身份连接,并创建以下触发器: 请注意,在出现文件号提示时,输入相关文件号(v$datafile 中的 rfile# 值) CREATE OR REPLACE TRIGGER corrupt_trigger AFTER INSERT ON scott.s REFERENCING OLD AS p_old NEW AS new_p FOR EACH ROW DECLARE corrupt EXCEPTION; BEGIN IF (dbms_rowid.rowid_block_number(:new_p.rowid)=&blocknumber) and (dbms_rowid.rowid_relative_fno(:new_p.rowid)=&filenumber) THEN RAISE corrupt; END IF; EXCEPTION WHEN corrupt THEN RAISE_APPLICATION_ERROR(-20000, 'Corrupt block has been formatted'); END; / 出现块编号提示时,输入坏块的块编号。 出现文件号提示时,输入损坏的数据文件的相关文件号(v$datafile 中的 rfile# 值)。 第 7 步 - 为受影响的数据文件中的表分配空间。 如果使用的是自动段空间管理的表空间(ASSM),因为ASSM表空间extent的分配是由自己决定的,可能需要多次运行本步骤来分配多个extents, 并且定期查看视图dba_extents确保空闲空间已经分配出去。 首先通过查询 dba_free_space 查找 extent 大小 SQL> Select BYTES from dba_free_space where file_id=<file no> and <corrupt block no> between block_id and block_id + blocks -1; BYTES ---------------- ---------- ---------- ---------- ---------- ------------ 65536 如果使用 64 K, 例如,从 E:\xxxx\test.ORA 下面分配 64 K 的空间,如下例所示: 例如,从 E:\xxxx\test.ORA 下面分配 64 K 的空间,如下例所示: SQL> alter table scott.s allocate extent (DATAFILE 'E:\xxxx\test.ORA' SIZE 64K); 如果使用 1M, SQL> Select BYTES from dba_free_space where file_id=<file no> and <corrupt block no> between block_id and block_id + blocks -1; BYTES ---------------- ---------- ---------- ---------- ---------- ------------ 1048576 例如,从 E:\xxxx\test.ORA 下面分配 1M 的空间,如下例所示: SQL> alter table scott.s allocate extent (DATAFILE 'E:\xxxx\test.ORA' SIZE 1M); 或者 使用下面的 for 循环 BEGIN for i in 1..1000000 loop EXECUTE IMMEDIATE 'alter table scott.s allocate extent (DATAFILE '||'''E:\xxxx\test.ORA''' ||'SIZE 64K) '; end loop; end ; / 请注意,您需要相应地更改大小(1M、64K 或 128k),并按照要求更改循环的次数。 继续分配空间直到坏块成为 scott.s 的一部分 — 使用以下查询进行检查: SQL> select segment_name, segment_type, owner from dba_extents where file_id = <Absolute file number> and <corrupt block number> between block_id and block_id + blocks -1 ; 注意:明智的做法是确保数据文件的 AUTOEXTEND 处于关闭状态,以防止其扩展 第 8 步 - 向虚拟表中插入数据以格式化块 示例代码(取决于表空间的大小,循环的次数可能发生变化): BEGIN FOR i IN 1..1000000000 LOOP INSERT /*+ APPEND */ INTO scott.s select i, lpad('REFORMAT',3092, 'R') from dual; commit ; END LOOP; END; 或者 BEGIN FOR i IN 1..1000000000 LOOP INSERT INTO scott.s VALUES(i,'x'); END LOOP; END; / 或使用以下包含 2 个循环的代码: Begin FOR i IN 1..1000000000 loop for j IN 1..1000 loop Insert into scott.s VALUES(i,'x'); end loop; commit; END LOOP; END; 每向表中插入一行就会触发触发器,且一旦向坏块中插入第一行数据,就会产成 ORA-20000 异常。 第 9 步 - 通过运行 DBV 和 Rman 备份确定数据文件中的坏块情况 在损坏的数据文件上运行 dbverify。此操作将不会显示坏块。 RMAN 备份不会报告此块上的任何错误。 第 10 步 - 删除第 4 步中创建的虚拟表 SQL> DROP TABLE scott.s ; 如果版本为 10gr1 及以上,同时使用purge选项以清空回收站 第 11 步 – 执行手动日志切换和检查点 第 11 步 – 执行手动日志切换和检查点 执行两次日志切换和检查点,以便将在内存中格式化的块写入到磁盘并使 dbverify 不再报告错误 SQL>Alter system switch logfile ; --> Do this couple of time SQL>Alter system checkpoint ; 第 12 步 - 删除第 6 步中创建的触发器 SQL> DROP triggercorrupt_trigger ; 同样要注意: Bug 7381632 - ORA-1578 Free corrupt blocks may not be reformatted when Flashback is enabled
Comment