如果自己搞不定可以找诗檀软件专业ORACLE数据库修复团队成员帮您恢复!

诗檀软件专业数据库修复团队

服务热线 : 13764045638 QQ号:47079569 邮箱:service@parnassusdata.com

   

适用于:

Oracle Database - Enterprise Edition – 版本8.1.7.0 12.1.0.1 [Release 8.1.7 to 12.1] Oracle Database - Standard Edition – 版本8.1.7.0 12.1.0.1 [Release 8.1.7 to 12.1] 本文信息适用于任何平台。 *** 10-Feb-2011检查相关性*** *** 3-Jul-2015检查相关性***

症状

目的: 本文的目的是提供更新lob列的脚本,其使用空的lob引用一个由于NOLOGGING操作标记为corruptedlob块。 lob列被类似SELECTsql语句访问,这会防止错误ORA-1578 / ORA-26040 ,且如果需要的话可以生成表导出。 问题: 在表中读取lob列时,生成ORA-1578 ORA-26040

ORA-1578 : ORACLE data block corrupted (file # %s, block # %s) ORA-26040: Data block was loaded using the NOLOGGING option

对生成错误的数据文件dbverify失败并生成错误DBV-200 rdbms 版本 < 10.2.0.4)或DBV-201 rdbms 版本>= 10.2.0.4):

DBV-00200: Block, dba <dba number>, already marked corrupted DBV-00201: Block, DBA <rdba>, marked corrupt for invalid redo application

例如:

dbv file=/oracle/oradata/data.dbf blocksize=8192 DBV-00200: Block, dba 54528484, already marked corrupted .....

可以使用dba获取相关的文件号和块号:

相关文件号: SQL> select dbms_utility.data_block_address_file(54528484) from dual; DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(54528484) ---------------------------------------------- 13 块号: SQL> select dbms_utility.data_block_address_block(54528484) from dual; DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(54528484) ----------------------------------------------- 2532

重要事项 ORA-26040 不与ORA-1578一起生成,则块由于其他原因损坏且可以使用Block Media 恢复来修复类似RMAN BLOCKRECOVER的损坏。

原因

LOB 段被定义为NOLOGGING ,且在数据文件恢复后LOB 块被Oracle标记为corrupted

解决方案

识别引用lob段的表  当使用sql语句访问lob列时,错误示例:

ORA-01578 : ORACLE data block corrupted (file #13 block # 2532) ORA-01110 : datafile 10: '/oracle/oradata/data.dbf' ORA-26040 : Data block was loaded using the NOLOGGING option.

1. 查询 dba_extents来找出lob段名。

从以上的错误ORA-1110获取数据文件号,它表示绝对文件号 (AFN) ,并运行下一个查询来识别受影响的Lob段:

select owner, segment_name, segment_type from   dba_extents where  file_id = 10 and    2532 between block_id and block_id + blocks - 1;

在示例中,它返回:

owner=SCOTT segment_name=SYS_LOB0000029815C00006$$ segment_type=LOBSEGMENT

2. 查询 dba_lobs 以识别table_name lob列名:

select table_name, column_name from   dba_lobs where  segment_name = 'SYS_LOB0000029815C00006$$' and    owner = 'SCOTT';

在示例中,它返回:

table_name  = EMP column_name = EMPLOYEE_ID_LOB

XMLTYPE

这是lob段可能与XMLTYPE 相关的情况:

select table_name from dba_lobs where segment_name = 'SYS_LOB0000013274C00003$$' and owner = 'SCOTT'; TABLE_NAME ------------------------------ TABLE_WITH_XML_COLUMN SQL> describe scott.TABLE_WITH_XML_COLUMN Name Null?      Type --------------- ------------ FILENAME        VARCHAR2(64) XML_DOCUMENT    XMLTYPE

在这里XML_DOCUMENT lob 列。 修复

3. 通过运行以下plsql脚本,识别表rowid的引用损坏lob段块:

drop table bad_rows; create table bad_rows (row_id ROWID ,oracle_error_code number); set concat off set serveroutput on declare n number; error_code number; bad_rows number := 0; ora1578 EXCEPTION; ora600 EXCEPTION; PRAGMA EXCEPTION_INIT(ora1578, -1578); PRAGMA EXCEPTION_INIT(ora600, -600); begin for cursor_lob in (select rowid rid, &&lob_column from &&table_owner.&table_with_lob) loop begin n:=dbms_lob.instr(cursor_lob.&&lob_column,hextoraw('889911')) ; exception when ora1578 then bad_rows := bad_rows + 1; insert into bad_rows values(cursor_lob.rid,1578); commit; when ora600 then bad_rows := bad_rows + 1; insert into bad_rows values(cursor_lob.rid,600); commit; when others then error_code:=SQLCODE; bad_rows := bad_rows + 1; insert into bad_rows values(cursor_lob.rid,error_code); commit; end; end loop; dbms_output.put_line('Total Rows identified with errors in LOB column: '||bad_rows); end; / undefine lob_column select * from bad_rows;

当由变量值提示,以下我们的示例:

Enter value for lob_column: EMPLOYEE_ID_LOB Enter value for table_owner: SCOTT Enter value for table_with_lob: EMP

XMLTYPE

如果lob段与XMLTYPE相关,则使用cursor_lob.&&lob_column.getCLOBVal() (CLOB ) 以上plsql中的getBLOBVal() (BLOB)替换cursor_lob.&&lob_columnCLOB的整个列将会是:

n:=dbms_lob.instr(cursor_lob.&&lob_column.getCLOBVal(),hextoraw('889911')) ;

与由变量提示时类似,在我们的例子中会是:

Enter value for lob_column: XML_DOCUMENT Enter value for table_owner: SCOTT Enter value for table_with_lob: TABLE_WITH_XML_COLUMN

4. 以空lob更新lob列从而防止ORA-1578 ORA-26040

SQL> set concat off SQL> update &table_owner.&table_with_lob set &lob_column = empty_blob()  where rowid in (select row_id from bad_rows);

如果&lob_column 是一个CLOB NCLOB数据类型,用empty_clob替换empty_blob

XMLTYPE

如果lob 段与XMLTYPE相关,使用XMLType.createXML('') 而不是空的lob

SQL> update scott.TABLE_WITH_XML_COLUMN set XML_DOCUMENT = XMLType.createXML('')  where rowid in (select row_id from bad_rows);

5. 观察

  • 注意损坏lob块中的数据是不可拯救的,因为那里的信息是不可读的。块当前以NOLOGGING 格式损坏。
  • 设置损坏lob empty lob 会将之前映射到该lob的块添加到freelist。最终当 PCTVERSION RETENTION criteria导致空间被拯救并重新用于新数据,在相同LOB开中会再次看到错误 ORA-1578/ORA-26040Empty lob 表示在该列中被引用的损坏lobpointer被清理。损坏块本身未被访问/修复;它仅在log段的freelist元数据中被标记为free 。如果lob段仍使用更多空间继续增长,损坏块可以被尝试再使用(因为块是free)且对于请求更多空间的lob段的INSERTUPDATE语句会再次生成损坏错误。在此情况下应用以上过程后,lob 段能被移动到新的段:

alter table &table_owner.&table_with_lob move LOB (&&lob_column) store as (tablespace &tablespace_name);

  • 如果执行了alter table MOVE ,检查UNUSABLE表索引为REBUILD,因为警告日志可能有下一个信息:

Some indexes or index [sub]partitions of table <name> have been marked unusable

  • Dbverify仍会生成错误DBV-200 / DBV-201 ,直到被标记为corrupted的块的extent被另一个段再使用。
  • 在以上的plsql代码中,被发送到dbms_lob.instr中的过程hextoraw的值889911 是验证lob内容的fake值。dbms_lob.instr 应该不能找到该字符串,所以变量 "n" 应该始终返回0

参考

NOTE:290161.1 - The Gains and Pains of Nologging Operations in a Data Guard Environment NOTE:794505.1 - ORA-1578 / ORA-26040 Corrupt blocks by NOLOGGING - Error explanation and solution