miércoles, 18 de abril de 2018

DBMS_REPAIR

Si se te han presentado problemas de corrupción de bloques de datos y no tienes implementado backup con RMAN o tu respaldo de RMAN no está a un punto del tiempo para resolver el problema de corrupción de datos, hay otra forma de reparar estos bloques con el paquete DBMS_REPAIR.

Oracle proporciona varias opciones para detectar y reparar bloques corruptos entre ellas DBMS_REPAIR, paquete con funcionalidades para las tareas de detección y reparación de bloques corruptos.


Descripción DBMS_REPAIR

Procedure Name Description
ADMIN_TABLES Permite crear, borrar y eliminar las tablas administrativas repair o orphan key . Nota: These Por defecto se crean en el SYS.
CHECK_OBJECT Detecta y reporte la corrupcion de bloques en tablas o indices.
DUMP_ORPHAN_KEYS Reporta los bloques de datos corruptos para los indices
FIX_CORRUPT_BLOCKS Marca los bloques de datos corruptos que previamente fueron identificados por CHECK_OBJECT procedure
REBUILD_FREELISTS Rebuilds the free lists of the object
SEGMENT_FIX_STATUS Provides the capability to fix the corrupted state of a bitmap entry when segment space management is AUTO
SKIP_CORRUPT_BLOCKS When used, ignores blocks marked corrupt during table and index scans. If not used, you get error ORA-1578 when encountering blocks marked corrupt.


Lo primero que hay que hacer antes de usar el DBMS_REPAIR es detectar los objetos que tienen los bloques corruptos, pueden revisar "http://oracle-y-yo.blogspot.com/2018/04/reparar-tablas-con-bloques-de-datos.html" y ver los modos de detectar los objetos con bloques corruptos.

Pasos para el uso del DBMS_REPAIR

1 Crear las estructuras REPAIR_TABLE y ORPHAN_KEY_TABLE
REPAIR_TABLE almacena los id de los bloques corruptos para los segmentos a nivel de tabla y ORPHAN_KEY_TABLE los id de los bloques corruptos a nivel de indices

--Creacion de REPAIR_TABLE
BEGIN
DBMS_REPAIR.ADMIN_TABLES (
     TABLE_NAME => 'REPAIR_TABLE',
     TABLE_TYPE => dbms_repair.repair_table,
     ACTION     => dbms_repair.create_action,
     TABLESPACE => 'USERS');
END;
/

--Creacion de ORPHAN_KEY_TABLE
BEGIN
DBMS_REPAIR.ADMIN_TABLES (
     TABLE_NAME => 'ORPHAN_KEY_TABLE',
     TABLE_TYPE => dbms_repair.orphan_table,
     ACTION     => dbms_repair.create_action,
     TABLESPACE => 'USERS');
END;
/
--TABLESPACE Es recomendable establecer, sino se crea en el default
--del SYS


2 Detectar la corrupción
Buscar los bloques de datos de tablas e indices.

--REPAIR_TABLE

--Detectar los bloques corruptos a nivel de tabla.
--Esto se realiza por cada objeto tabla, los id de los bloques
--corruptos se almacenaran en la tabla REPAIR_TABLE
SET SERVEROUTPUT ON
DECLARE num_corrupt INT;
BEGIN
num_corrupt := 0;
DBMS_REPAIR.CHECK_OBJECT (
     SCHEMA_NAME => 'SCOTT',
     OBJECT_NAME => 'DEPT',
     REPAIR_TABLE_NAME => 'REPAIR_TABLE',
     CORRUPT_COUNT =>  num_corrupt);
DBMS_OUTPUT.PUT_LINE('number corrupt: ' || TO_CHAR (num_corrupt));
END;
/
--ORPHAN_KEY_TABLE
--Detectar los bloques corruptos a nivel de indices.
--Esto se realiza por cada objeto tabla, los id de los bloques
--corruptos se almacenaran en la tabla ORPHAN_KEY_TABLE. Por cada
--indice que tenga la tabla se tendra que ejecutar la rutina
DECLARE num_orphans INT;
BEGIN
num_orphans := 0;
DBMS_REPAIR.DUMP_ORPHAN_KEYS (
     SCHEMA_NAME => 'SCOTT',
     OBJECT_NAME => 'PK_DEPT',
     OBJECT_TYPE => dbms_repair.index_object,
     REPAIR_TABLE_NAME => 'REPAIR_TABLE',
     ORPHAN_TABLE_NAME=> 'ORPHAN_KEY_TABLE',
     KEY_COUNT => num_orphans);
DBMS_OUTPUT.PUT_LINE('orphan key count: ' || TO_CHAR(num_orphans));
END;
/

SQL para ver los datos de los bloques corruptos.

--Select a la tabla REPAIR_TABLE
SELECT OBJECT_NAME, BLOCK_ID, CORRUPT_TYPE, MARKED_CORRUPT,
       CORRUPT_DESCRIPTION, REPAIR_DESCRIPTION
     FROM REPAIR_TABLE;


3 Reparar los bloques corruptos

A nivel de tabla

--Ejecutar la reparación
SET SERVEROUTPUT ON
DECLARE num_fix INT;
BEGIN 
num_fix := 0;
DBMS_REPAIR.FIX_CORRUPT_BLOCKS (
     SCHEMA_NAME => 'SCOTT',
     OBJECT_NAME=> 'DEPT',
     OBJECT_TYPE => dbms_repair.table_object,
     REPAIR_TABLE_NAME => 'REPAIR_TABLE',
     FIX_COUNT=> num_fix);
DBMS_OUTPUT.PUT_LINE('num reparaciones: ' || TO_CHAR(num_fix));
END;
/
SQL*Plus outputs the following line:
num reparaciones: 1

--Si num reparaciones no da igual  al numero de registros dentro de REPAIR_TABLE esto
--quiere decir que no se realizó la reparacion de forma completa.

--SQL para determinar si la reparaciión fue realizada.
SELECT OBJECT_NAME, BLOCK_ID, MARKED_CORRUPT
     FROM REPAIR_TABLE;

OBJECT_NAME                      BLOCK_ID MARKED_COR
------------------------------ ---------- ----------
DEPT                                    3 TRUE
 


A nivel de indice

--Ejecutar la reparación, por cada indice de la tabla se tendra
--que realizar
SET SERVEROUTPUT ON
DECLARE num_orphans INT;
BEGIN
num_orphans := 0;
DBMS_REPAIR.DUMP_ORPHAN_KEYS (
     SCHEMA_NAME => 'SCOTT',
     OBJECT_NAME => 'PK_DEPT',
     OBJECT_TYPE => dbms_repair.index_object,
     REPAIR_TABLE_NAME => 'REPAIR_TABLE',
     ORPHAN_TABLE_NAME=> 'ORPHAN_KEY_TABLE',
     KEY_COUNT => num_orphans);
DBMS_OUTPUT.PUT_LINE('orphan key count: ' || TO_CHAR(num_orphans));
END;
/
OUTPUT
orphan key count: 3


Hay que tener en cuenta que no siempre se puede obtener la reparación completa

4 Saltándose los bloques corruptos
El procedimiento SKIP_CORRUPT_BLOCKS habilita o deshabilita la omisión de bloques dañados durante la búsqueda en índice y tabla del objeto especificado. Cuando el objeto es una tabla, la omisión se aplica a la tabla y sus índices. Cuando el objeto es un clúster, se aplica a todas las tablas del clúster y a sus respectivos índices

--Habilitar el salto de bloques corruptos
BEGIN
DBMS_REPAIR.SKIP_CORRUPT_BLOCKS (
     SCHEMA_NAME => 'SCOTT',
     OBJECT_NAME => 'DEPT',
     OBJECT_TYPE => dbms_repair.table_object,
     FLAGS => dbms_repair.skip_flag);
END;
/

Querying scott's tables using the DBA_TABLES view shows that SKIP_CORRUPT is enabled for table scott.dept.
SELECT OWNER, TABLE_NAME, SKIP_CORRUPT FROM DBA_TABLES
    WHERE OWNER = 'SCOTT';

OWNER                          TABLE_NAME                     SKIP_COR
------------------------------ ------------------------------ --------
SCOTT                          ACCOUNT                        DISABLED
SCOTT                          BONUS                          DISABLED
SCOTT                          DEPT                           ENABLED
SCOTT                          DOCINDEX                       DISABLED
SCOTT                          EMP                            DISABLED
SCOTT                          RECEIPT                        DISABLED
SCOTT                          SALGRADE                       DISABLED
SCOTT                          SCOTT_EMP                      DISABLED
SCOTT                          SYS_IOT_OVER_12255             DISABLED
SCOTT                          WORK_AREA                      DISABLED
 



lunes, 16 de abril de 2018

Reparar tablas con bloques de datos corruptos ORA-01578:

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.

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





miércoles, 4 de abril de 2018

Instala Oracle 12C ASM+Database

Instalación y configuración de la infraestructura GRID mas la instalación de una base de datos con almacenamiento ASM.