lunes, 31 de agosto de 2020

Reparacion ORA-01578 y ORA-26040 en columna BLOB

Hola , en esta ocacion les comento, un cliente tiene una tabla que contiene una columna de imagenes (blob), resulta que la columna que contiene las imagnes se corrompio y se recibia el siguiente error:

 

y al realizar cualquier accion de adicion/modificacion sobre la tabla, se recibia el siguiente error:

ORA-01578: ORACLE data block corrupted (file # 7, block # 34982)
ORA-01110: data file 7: '+DATA/SISTEMA_01/DATAFILE/imagen_lob.424.1032123411'
ORA-26040: Data block was loaded using the NOLOGGING option

Hagamos una pausa y veamos lo siguiente:
1) Significa que los datos ya estaban dañados, principalmente debido a corrupciones lógicas,
no es probable que sea una falla del hardware. Pero la pregunta clave es:
¿Podemos recuperar los datos dañados?
 
 2)Por defecto, las tablas e indices se crean en logging, a menos que se aplique la clausula durante la creación de la tabla o el tablespace.

Este parametro es completamente ignorado si la base de datos está configurada con FORCE LOGGING.


LOGGING:
Cada vez que la base ejecuta un DML o un DDL o un COMMIT, Oracle escribe  en el redo log buffer, que despues es enviado a los redo log files, convirtiendoce en los archive log files (si la base esta en archivelog mode).

Cuando la transacción es realizada permanente con un COMMIT, se crea un nuevo registro en el redolog buffer y asigna un nuevo SCN  al cambio.

Este es el mecanismo de proteccion que tiene la base para que en caso de tener que hacer un recover, cuente con toda la información a ser aplicada a los datafiles almacenada desde los redolog o archive log.

NOLOGGING:

Solo afecta a los direct-path load que se hagan a la base de datos. No afecta a los DML convencionales como INSERT, UPDATE, DELETE.

 como validar los bloques corruptos en un datafile:

 select * from dba_extents where file_id = 7 and 34982 between block_id and block_id + blocks - 1;

Solucion: 

1) crear tabla de validacion registros malos
CREATE TABLE esquema.corruptos_blobs
(corrupt_rowid rowid, err_num number)
TABLESPACE REPARA_TABLA_IMAGEN;


2) procedimiento que valida los registos con problemas,
-- FOTO      &&blob_columna
-- ESQUEMA   &tabla_owner
-- FOTOS     &tabla_con_blob

declare
error_1578 exception;
error_1555 exception;
error_22922 exception;
pragma exception_init(error_1578,-1578);
pragma exception_init(error_1555,-1555);
pragma exception_init(error_22922,-22922);
num number;
begin
for cursor_lob in (select rowid r, &&
blob_columna from &tabla_owner..&tabla_con_blob) loop
begin
num := dbms_lob.instr (cursor_lob.&&
blob_columna , hextoraw ('889911')) ;
exception
when error_1578 then
insert into desarrollo.
corruptos_blobs values (cursor_lob.r, 1578);
commit;
when error_1555 then
insert into desarrollo.
corruptos_blobs values (cursor_lob.r, 1555);
commit;
when error_22922 then
insert into desarrollo.
corruptos_blobs values (cursor_lob.r, 22922);
commit;
end;
end loop;
end;


3) marcar los registros con problemas

update ESQUEMA.FOTOS
set foto = empty_blob()
where rowid in (select corrupt_rowid from equema.
corruptos_blobs);
commit;

4) realizar exportacion de los registros

[oracle@boston]$ vi exparameter.par
directory=mydirectorio
dumpfile=tbl_fotos.dmp
logfile=tbl_fotos.log
tables=totos
query=foto:"where rowid not in (select corrupt_rowid from esquema.
corruptos_blobs)"

expdp \"usuario/clave\" parfile=exparameter.par
exp \"usuario/clave\" TABLES=fotos query=\"where rowid not in \(select corrupt_rowid from esquema.
corruptos_blobs\)\" FILE=exp_tabla.dmp log=exp_tabla.log