oracle ora1578,ORA-1578 ORA-26040 in a LOB segment (Doc ID 293515.1)

Purpose:

The purpose of this article is to provide a script to update a lob column, that is referencing a lob block marked as corrupted due to NOLOGGING operations, with an empty lob.

It will avoid errors ORA-1578 / ORA-26040 when the lob column is accessed by a sql statement like a SELECT and a table export can be produced if needed.

Problem:

ORA-1578 and ORA-26040 are produced when reading a lob column in a table:

ORA-1578 : ORACLE data block corrupted (file # %s, block # %s)

ORA-26040: Data block was loaded using the NOLOGGING option

dbverify for the datafile that produces the errors fails with error DBV-200 (rdbms version < 10.2.0.4) or DBV-201 (rdbms version >= 10.2.0.4):

DBV-00200: Block, dba , already marked corrupted

DBV-00201: Block, DBA , marked corrupt for invalid redo application

Example:

dbv file=/oracle/oradata/data.dbf blocksize=8192

DBV-00200: Block, dba 54528484, already marked corrupted

.....

The dba can be used to get the relative file number and block number:

Relative File number:

SQL> select dbms_utility.data_block_address_file(54528484) from dual;

DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(54528484)

----------------------------------------------

13

Block Number:

SQL> select dbms_utility.data_block_address_block(54528484) from dual;

DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(54528484)

-----------------------------------------------

2532

IMPORTANT

When ORA-26040 is not produced along with ORA-1578 the block is then corrupt by a different reason and Block Media recovery can be used to repair the corruption like RMAN BLOCKRECOVER.

Cause

LOB segment has been defined as NOLOGGING and LOB Blocks were marked as corrupted by Oracle after a datafile recovery.

Solution

Identify the table referencing the lob segment

Error example when accessing the lob column by a sql statement:

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. Query dba_extents to find out the lob segment name.

Take the Data File number from the error ORA-1110 above as it represents the absolute file number (AFN) and run the next query to identify the affected Lob Segment:

select owner, segment_name, segment_type

from   dba_extents

where  file_id = 10

and    2532 between block_id and block_id + blocks - 1;

In our example it returned:

owner=SCOTT

segment_name=SYS_LOB0000029815C00006$$

segment_type=LOBSEGMENT

2. Query dba_lobs to identify the table_name and lob column name:

select table_name, column_name

from   dba_lobs

where  segment_name = 'SYS_LOB0000029815C00006$$'

and    owner = 'SCOTT';

In our example it returned:

table_name  = EMP

column_name = EMPLOYEE_ID_LOB

XMLTYPE

There is the case where the lob segment might be associated to a 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 is the lob column in this case.

Fix

3. Identify the table rowid's referencing the corrupted lob segment blocks by running the following plsq script:

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;

PRAGMA EXCEPTION_INIT(ora1578, -1578);

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 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;

When prompted by variable values and following our example:

Enter value for lob_column: EMPLOYEE_ID_LOB

Enter value for table_owner: SCOTT

Enter value for table_with_lob: EMP

XMLTYPE

If the lob segment is related to a XMLTYPE, then replace cursor_lob.&&lob_column by cursor_lob.&&lob_column.getCLOBVal() (CLOB ) or getBLOBVal() (BLOB) in the above plsql; the entire line for a CLOB will then be:

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

Similarly when prompted by variable values, in our example it would be:

Enter value for lob_column: XML_DOCUMENT

Enter value for table_owner: SCOTT

Enter value for table_with_lob: TABLE_WITH_XML_COLUMN

4. Update the lob column with empty lob to avoid ORA-1578 and 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);

If &lob_column is a CLOB datatype, replace empty_blob by empty_clob.

XMLTYPE

If the lob segment is related to a XMLTYPE use XMLType.createXML('') instead of empty lob:

SQL> update scott.TABLE_WITH_XML_COLUMN

set XML_DOCUMENT = XMLType.createXML('')

where rowid in (select row_id from bad_rows);

5. Observations

Note that the data inside the corrupt lob blocks is not salvageable because the information there is not readable. The block is now corrupt with NOLOGGING format.

Setting the corrupt lob to empty lob will add the blocks formerly mapped to this lob to the freelist.  Eventually when PCTVERSION or RETENTION criteria causes the space to be salvaged and reused for new data, error ORA-1578/ORA-26040 can be seen again in the same LOB blocks. Empty lob means that the pointer to the corrupt lob referenced in that column is cleared. The corrupt block itself is not touched/repaired; it is just marked as free in the freelist metadata for the lob segment. If the lob segment continues growing using more space, the corrupt block can be attempted to be reused (as the block is free) and corruption error will be produced again for an INSERT or an UPDATE of the lob segment requesting more space.  In that case and after applying the above procedure the lob segment can be moved to a new segment:

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

If alter table MOVE is executed check for UNUSABLE table indexes to be REBUILD as the alert log may have the next messages:

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

dbverify will still produce errors DBV-200 / DBV-201 until the extent of the block marked as corrupted is reused by another segment.

In the plsql code above, the value 889911 passed to procedure hextoraw in dbms_lob.instr is a fake value to verify the lob content. dbms_lob.instr is not supposed to find that string so the variable "n" should always return 0.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值