Si al realizar consultas de tablas o en los logs de la base de datos se te presentan el mensaje de ORA-01578, esto quiere decir que se han corrompido bloques de datos en o los datafiles, esto se puede originar por daños físico o lógicos de los datos.
1-Identificar el segmento corrupto
Lo primero que debemos de realizar es identificar cual es el datafile y segmento que tiene el o los bloques corruptos. Podemos usar el database verify "dbv" o analizar los objetos hasta dar con los que den el error.
DBV
Sabiendo el datafile con el problema lo analizaremos con el dbv para determinar los bloques corruptos
Una vez obtenido los bloques corruptos vamos a determinar de que segmento proviene.
Crear el procedimiento CDBA para a partir del bloque sel SO obtener el bloque de la base de datos.
Una vez creado lo invocamos con los datos del DBV, para ello necesitamos saber el id del datafile
Identificar con el ANALIZE
Listo, a tenemos identificado el segmento
2 Realizar la recuperación o eliminación del bloque corrupto
Lo que mejor podemos hacer es realizar una recuperación con el RMAN ya sea a nivel del datafile o siendo mas especifico a nivel de bloque. Lo mas fácil, restore y recover. Para esto es necesario e imprensindible tener la base de datos en archivelog y tener un respaldo indoneo para realizar la recuperación.
RMAN
Pero que pasa si no tenemos una estrategia de respaldo con RMAN?, bueno no hay que echarse a llorar, si hay una forma de salir de esos errores, pero segun el caso podemos tener una leve perdida de información ya que vamos a transferir los datos a una nueva estructura pero omitiendo lo datos relacionados a los bloques corruptos.
SIN RMAN
ORA-01578: ORACLE data block corrupted (file # , block # )
ORA-01578: ORACLE data block corrupted (file # 2, block # 88580)
|
1-Identificar el segmento corrupto
Lo primero que debemos de realizar es identificar cual es el datafile y segmento que tiene el o los bloques corruptos. Podemos usar el database verify "dbv" o analizar los objetos hasta dar con los que den el error.
DBV
Sabiendo el datafile con el problema lo analizaremos con el dbv para determinar los bloques corruptos
//Desde un CMD ejecutamos el DBV
>dbv userid=control/oracle10g file =E:\oracle\data\D7IPROD\datafile\USER01.DBF blocksize=8192
//El resultado va a ser una lista de los bloques corruptos con un resumen
DBV-00201: Block, DBA 38428646, marked corrupt for invalid redo application
DBV-00201: Block, DBA 38428647, marked corrupt for invalid redo application
DBVERIFY - Verification complete
Total Pages Examined : 782088
Total Pages Processed (Data) : 777097
Total Pages Failing (Data) : 0
Total Pages Processed (Index): 1
Total Pages Failing (Index): 0
Total Pages Processed (Lob) : 21
Total Pages Failing (Lob) : 0
Total Pages Processed (Other): 4905
Total Pages Processed (Seg) : 34
Total Pages Failing (Seg) : 0
Total Pages Empty : 30
Total Pages Marked Corrupt : 2
Total Pages Influx : 0
Total Pages Encrypted : 0
Highest block SCN : 1709553936 (1293.1709553936)
|
Una vez obtenido los bloques corruptos vamos a determinar de que segmento proviene.
Crear el procedimiento CDBA para a partir del bloque sel SO obtener el bloque de la base de datos.
//Crear en la base de datos
SQLPLUS>CREATE OR REPLACE PROCEDURE cdba ( iblock VARCHAR2, imode VARCHAR2 ) AS
x NUMBER;
digits# NUMBER;
results NUMBER := 0;
file# NUMBER := 0;
block# NUMBER := 0;
cur_digit CHAR(1);
cur_digit# NUMBER;
/*Creavo por VEM
TFTS: Converting DBA's (Database Addresses) to File # and Block # (Doc ID 113005.1)
*/
BEGIN
IF upper(imode) = 'H' THEN
digits# := length( iblock );
FOR x IN 1..digits# LOOP
cur_digit := upper(substr( iblock, x, 1 ));
IF cur_digit IN ('A','B','C','D','E','F') THEN
cur_digit# := ascii( cur_digit ) - ascii('A') +10;
ELSE
cur_digit# := to_number(cur_digit);
END IF;
results := (results *16) + cur_digit#;
END LOOP;
ELSE
IF upper(imode) = 'D' THEN
results := to_number(iblock);
ELSE
dbms_output.put_line('H = Hex Input ... D = Decimal Input');
RETURN;
END IF;
END IF;
file# := dbms_utility.data_block_address_file(results);
block# := dbms_utility.data_block_address_block(results);
dbms_output.put_line('.');
dbms_output.put_line( 'The file is ' || file# );
dbms_output.put_line( 'The block is ' || block# );
END;
/
|
Una vez creado lo invocamos con los datos del DBV, para ello necesitamos saber el id del datafile
//Identificar el ID del datafile
SQLPLUS> select file#, name from v$datafile where name='E:\ORACLE\DATA\D7IPROD\DATAFILE\USER01.DBF';
FILE# NAME
------------------------------------------------------------------------------------------
4 E:\ORACLE\DATA\D7IPROD\DATAFILE\USER01.DBF
//Tomamos del resultado de DBV los numero de bloques
SQLPLUS begin cdba(50513350,'D'); end;\
Result
.
The file is 12
The block is 181702
//Una vez obtenido el numero de bloque vamos a ver a que segmento pertenece
SQLPLUS>select segment_name, segment_type, owner
from dba_extents
where file_id = 9
and 181702 between block_id
and block_id + blocks -1;
Results
segment_name segment_type owner -----------------------------------------------------------------------------------MI_TABLA_MALA TABLE HR |
Identificar con el ANALIZE
//Con esto validamos la tabla y nos retornara error si tiene bloques corruptos
BEGIN
SYS.DBMS_STATS.GATHER_TABLE_STATS (OwnName => 'HR',
TabName => 'MI_TABLA_MALA',
Estimate_Percent => 10,
Method_Opt => 'FOR ALL COLUMNS SIZE 1',
Degree => 4,
Cascade => FALSE,
No_Invalidate => FALSE);
END;
ORA-01578: bloque de datos ORACLE corrupto (archivo número 4, bloque número 679744)
ORA-01110: archivo de datos 9: 'E:\ORACLE\DATA\D7IPROD\DATAFILE\USERS01.DBF'
ORA-26040: Se ha cargado el bloq
|
Listo, a tenemos identificado el segmento
2 Realizar la recuperación o eliminación del bloque corrupto
Lo que mejor podemos hacer es realizar una recuperación con el RMAN ya sea a nivel del datafile o siendo mas especifico a nivel de bloque. Lo mas fácil, restore y recover. Para esto es necesario e imprensindible tener la base de datos en archivelog y tener un respaldo indoneo para realizar la recuperación.
RMAN
//Ponemos el datafile offline antes de iniciar la recuperación
RMAN> alter database datafile '/u01/app/oracle/oradata/orcl/user01.dbf' offline;
Statement processed
//Para saber el id del datafile en un sqlplus y ver el resultado select file#, name from v$datafile
RMAN> restore datafile 5;
channel ORA_DISK_1: starting datafile backup set restore
channel ORA_DISK_1: specifying datafile(s) to restore from backup set
channel ORA_DISK_1: restoring datafile 00005 to /u01/app/oracle/oradata/orcl/user01.dbf
channel ORA_DISK_1: reading from backup piece /backup/18rb3b6l_1_1
channel ORA_DISK_1: piece handle=/backup/18rb3b6l_1_1 tag=TAG20160719T124301
channel ORA_DISK_1: restored backup piece 1
channel ORA_DISK_1: restore complete, elapsed time: 00:00:01
Finished restore at
RMAN> recover datafile 5;
Starting recover at
using channel ORA_DISK_1
starting media recovery
media recovery complete, elapsed time: 00:00:00
Finished recover at
//Regresamos el datafile online una vez finalizado la recuperación
RMAN> alter database datafile '/u01/app/oracle/oradata/orcl/user01.dbf' online;
using target database control file instead of recovery catalog
Statement processed
|
Pero que pasa si no tenemos una estrategia de respaldo con RMAN?, bueno no hay que echarse a llorar, si hay una forma de salir de esos errores, pero segun el caso podemos tener una leve perdida de información ya que vamos a transferir los datos a una nueva estructura pero omitiendo lo datos relacionados a los bloques corruptos.
SIN RMAN
//Modificamos el nivel de registro de eventos
SQL> ALTER SYSTEM SET EVENTS='10231 trace name context forever,level 10' ;
//Procedemos a crear una nueva tabla a partir de la que presenta los errores de corrupción
SQL> CREATE TABLE mi_tabla_nueva AS SELECT * FROM mi_tabla_mala;
//Revisamos los datos creaado en mi_Tabla_nueba y luego borramos la tabla mi_tabla_mala.
SQL> DROP TABLE bad_table;
//realizamos el renombre de mi_Tabla_nueva a mi_tabla_mala
SQL> RENAME good_table TO bad_table;
//Desactivamos el nivel de eventos
ALTER SYSTEM SET EVENTS '10231 trace name context off';
|
muy util muchas gracias
ResponderEliminarExcelente post!! muchas gracias por compartir!
ResponderEliminar