📜 ⬆️ ⬇️

How to get rid of ORA-01410 by isolating intact data

At one time, I seriously got my hand on what task - on a number of tables, several lines were beaten as a result of compression and an Oracle bug. As a result, users with Fulskane received ORA-01410 according to such tables.
Consider the most difficult case - when there are no backups or indexes (in this case, the indexed columns can be obtained by scanning the index). In this case, the only option is to find the problematic ROWID and “go around” it from two sides, isolating the intact data.

First, let's remove the trace by the problematic request in order to get the initial data:
alter session set db_file_multiblock_read_count=1; alter session set events 'immediate trace name trace_buffer_on level 1048576'; alter session set events '10200 trace name context forever, level 1'; alter session set events '1410 trace name errorstack forever, level 10'; alter session set tracefile_identifier='ORA1410'; 


and run the problem query
 select count(1) from test.testtable; 

We find in record a record like this:
 ktrget2(): started for block <0x0645 : 0x3ce2c85b> objd: 0x00f842bb env: (scn: 0x0a21.9a61c1d8 xid: 0x0000.000.00000000 uba: 0x00000000.0000.00 statement num=0 parent xid: xid: 0x0000.000.00000000 scn: 0x0000.00000000 96sch: scn: 0x0000.00000000 mascn: (scn: 0x0a1f.ccec0b27) OBJD MISMATCH typ=6, seg.obj=16270011, diskobj=16268354, dsflg=100001, dsobj=16270011, tid=16270011, cls=1 


By the obtained value we get Block_number and Relative_fno:
 select dbms_utility.data_block_address_file(to_number('3ce2c85b', 'xxxxxxxx')) file#, dbms_utility.data_block_address_block(to_number('3ce2c85b', 'xxxxxxxx')) block# from dual; FILE# BLOCK# 243 2279515 

')
Additionally, we find the data_object_id of the problem object:
 select data_object_id from dba_objects where owner = 'test' and object_name = 'testtable'; data_object_id ---------------------- 16402245 


Based on the obtained values, we form a ROWID:
 select dbms_rowid.rowid_create(rowid_type => 1,object_number => 16402245,relative_fno => 243,block_number => 2279515,row_number => 0) from dual; ROWID=AA+kdFADzAAIshbAAA 

Well and, actually, what I mentioned at the beginning - we go around the problem line from all sides:
 insert into test.testtable_nocorrupt select /*parallel(8)*/ * from test.testtable where rowid<'AA+EK7ADzAAIshbAAA'; insert into test.testtable_nocorrupt select /*parallel(8)*/ * from test.testtable where rowid>='AA+EK7ADzAAIshcAAA'; 


I would like to note that such problems would most likely have been avoided by having the DB parameters set to db_block_checking / db_block_checksum = 'Full' or db_ultra_safe = 'data_and_index', which would load the processor somewhat (~ 5%, although this is discussed), but gave would be extra reliability.

Used notes Metalink:
Extracting Data from a Corrupt Table using ROWID Range Scans in Oracle8 and higher [ID 61685.1]
OERR: ORA-8103 "object no longer exists" / Troubleshooting, Diagnostic and Solution [ID 8103.1]

Source: https://habr.com/ru/post/155075/


All Articles