Hoy vamos a ver como detectar que se nos ha roto en casos de problemas de bloques corruptos de Oracle.
Lo primero que tenemos que tener en mente es tener la base de datos en modo archivelog y hacer copias periódicas con RMAN, pero , ¿que ocurre si no es así y tenemos una corrupción de datos?
Seguramente habremos perdido esos bloques. Pero, lo primero va a ser el saber que objetos lógicos tenemos corruptos .
Tenemos dos maneras de detectar la corrupción de datos
RMAN
Si tenemos la base de datos en modo archivelog ejecutaremos
rman target / nocatalog
run {
allocate channel d1 type disk;
backup check logical validate database;
release channel d1;
}
El comando validate de RMAN hará un chequeo de los bloques inválidos y nos los dejará en la vista v$database_block_corruption;
DBVERIFY
Si no tenemos la base de datos en modo archivelog, no podemos usar RMAN (a no ser que esté en modo MOUNT), asi que,usaermos dbv.
Oracle provee en todas las plataformas el comando de sistema operativo DBVERIFY (dbv) que nos permite el llevar a cabo una comprobación de la integridad física de los ficheros de la base de datos.Su gran ventaja es que no necesita corte de servicio y podemos ejecutarlo tranquilamente mientras los usuarios trabajan en la base de datos.
La sintaxis la podemos ver en http://docs.oracle.com/cd/A97630_01/server.920/a96652/ch13.htm , y su principal inconveniente es que debe lanzarse para cada uno de los datafiles de la base de datos.
Una manera rápida de automatizar el comando para toda la base de datos es mediante el siguiente script ejecutado como sys o system
spool /tmp/datafiles_corruptos.sh
set linesize 200
set heading off
set pagesize 200
select 'dbv file=' || name || ' blocksize=' || block_size ||
' feedback=' || round(blocks*.10,0)||
' logfile=' || file# || '.log'
from v$datafile;
Este script nos dejara un fichero /tmp/datafiles_corruptos.sh con tantas líneas como datafiles tenga la base de datos de la forma
dbv file=/opt/oracle/oradata/pruebas/tablespace_indices001.dbf blocksize=8192 feedback=3840 logfile=2
El comando dbv nos va a generar un fichero de log de nombre DATAFILE#.log, con lo que, mi consejo es crear un subdirectorio y lanzar el script /tmp/datafiles_corruptos.sh desde este subdirectorio, asi no llenaremos el path donde nos encontremos de ficheros de log.
EL detectar lo bloques inválidos es muy sencillo, solamente tenemos que ordenar por tamaño de fichero en el subdirectorio que tenemos los logs. Los ficheros que no tienen bloques corruptos tendrás un tamaño aproximado de 1 Km y su contenido será similar a :
DBVERIFY: Release 11.2.0.3.0 - Production on Jue Jun 6 13:14:28 2013 Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved. DBVERIFY - Iniciando verificación : FILE =/opt/oracle/oradata/pruebas/tablespace_indices018.dbf DBVERIFY - Verificación terminada Total de Páginas Examinadas : 153600 Total de Páginas Procesadas (Datos): 91682 Total de Páginas con Fallos (Datos): 0 Total de Páginas Procesadas (Índice): 28488 Total de Páginas con Fallos (Índice): 0 Total de Páginas Procesadas (Otras): 17288 Total de Páginas Procesadas (Seg): 1 Total de Páginas con Fallos (Seg): 0 Total de Páginas Vacías : 16142 Total de Páginas Marcadas como Corruptas: 0 Total de Páginas de Entrada : 0 Total de Páginas Cifradas : 0 SCN de Bloque Superior : 1961026896 (9.1961026896)
Los datafiles con bloques corruptos tendrán un tamaño mayor, y su contenido será
DBVERIFY: Release 11.2.0.3.0 - Production on Jue Jun 6 13:16:14 2013 Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved. DBVERIFY - Iniciando verificación : FILE = /opt/oracle/oradata/pruebas/SYSAUX01.DBF La página 45847 es de entrada - probablemente el medio físico esté corrupto Corrupt block relative dba: 0x00c0b317 (file 3, block 45847) Fractured block found during dbv: Data in bad block: type: 6 format: 2 rdba: 0x00c0b317 last change scn: 0x0009.5a58966b seq: 0x1 flg: 0x06 spare1: 0x0 spare2: 0x0 spare3: 0x0 consistency value in tail: 0x00000000 check value in block header: 0x5708 computed block checksum: 0x48fd La página 45849 está marcada como corrupta Corrupt block relative dba: 0x00c0b319 (file 3, block 45849) Completely zero block found during dbv: La página 45850 está marcada como corrupta Corrupt block relative dba: 0x00c0b31a (file 3, block 45850) Completely zero block found during dbv: . . . . . . La página 117911 es de entrada - probablemente el medio físico esté corrupto Corrupt block relative dba: 0x00c1cc97 (file 3, block 117911) Fractured block found during dbv: Data in bad block: type: 0 format: 0 rdba: 0x00000000 last change scn: 0x0000.00000000 seq: 0x0 flg: 0x00 spare1: 0x0 spare2: 0x0 spare3: 0x0 consistency value in tail: 0xc90c0601 check value in block header: 0x0 block checksum disabled DBVERIFY - Verificación terminada Total de Páginas Examinadas : 141312 Total de Páginas Procesadas (Datos): 41849 Total de Páginas con Fallos (Datos): 0 Total de Páginas Procesadas (Índice): 46801 Total de Páginas con Fallos (Índice): 0 Total de Páginas Procesadas (LOB) : 3100 Total de Páginas con Fallos (LOB) : 0 Total de Páginas Procesadas (Otras): 27154 Total de Páginas Procesadas (Seg): 0 Total de Páginas con Fallos (Seg): 0 Total de Páginas Vacías : 22352 Total de Páginas Marcadas como Corruptas: 56 Total de Páginas de Entrada : 6 Total de Páginas Cifradas : 0 SCN de Bloque Superior : 1961026953 (9.1961026953)
Con esto tendremos también la información en la vista v$database_block_corruption;, pero ¿que objetos son los que tenemos con problemas?
Si ejecutáis la consulta :
set linesize 200 set pagesize 200 SELECT e.owner, e.segment_type, e.segment_name, e.partition_name, c.file# , greatest(e.block_id, c.block#) corr_start_block# , least(e.block_id+e.blocks-1, c.block#+c.blocks-1) corr_end_block# , least(e.block_id+e.blocks-1, c.block#+c.blocks-1) - greatest(e.block_id, c.block#) + 1 blocks_corrupted , null description FROM dba_extents e, v$database_block_corruption c WHERE e.file_id = c.file# AND e.block_id <= c.block# + c.blocks - 1 AND e.block_id + e.blocks - 1 >= c.block# UNION SELECT s.owner, s.segment_type, s.segment_name, s.partition_name, c.file# , header_block corr_start_block# , header_block corr_end_block# , 1 blocks_corrupted , 'Segment Header' description FROM dba_segments s, v$database_block_corruption c WHERE s.header_file = c.file# AND s.header_block between c.block# and c.block# + c.blocks - 1 UNION SELECT null owner, null segment_type, null segment_name, null partition_name, c.file# , greatest(f.block_id, c.block#) corr_start_block# , least(f.block_id+f.blocks-1, c.block#+c.blocks-1) corr_end_block# , least(f.block_id+f.blocks-1, c.block#+c.blocks-1) - greatest(f.block_id, c.block#) + 1 blocks_corrupted , 'Free Block' description FROM dba_free_space f, v$database_block_corruption c WHERE f.file_id = c.file# AND f.block_id <= c.block# + c.blocks - 1 AND f.block_id + f.blocks - 1 >= c.block# order by file#, corr_start_block#;
Obtendréis un resultado similar a este
OWNER SEGMENT_TYPE SEGMENT_NAME PARTITION_NAME CORR_START_BLOCK# CORR_END_BLOCK# BLOCKS_CORRUPTED DESCRIPTION ----------- ------------------ ------------------------------------------------- ---------- ----------------- --- SYS TABLE WRH$_PGASTAT 3 45847 45847 1 SYSMAN TABLE MGMT_TARGET_ASSOC_ERROR 3 45851 45851 1 Segment Header
Como siempre, tenemos mas información y mas precisa en soporte oracle en :
- OERR: ORA-1578 «ORACLE data block corrupted (file # %s, block # %s)» Master Note [ID 1578.1]
- Note 28814.1 Handling Oracle Block Corruptions in Oracle7/8/8i/9i/10g
- Note 556733.1 DBMS_REPAIR script y Note 68013.1 DBMS_REPAIR example
- Physical and Logical Block Corruptions. All you wanted to know about it. [ID 840978.1]