El equivalente a CONSISTENT=Y con expdp

Hoy vamos a ver otra de esas entradas sumamente sencillas que nos ahorrarán un montón de tiempo.

Si intentamos hacer un exdp de una base de datos grande que hace un uso muy intensivo de secuencias, podemos encontrarnos problemas a la hora de la importación con las claves ajenas, esto es debido a que el export que hemos llevado a cabo no es consistente.

En la versión antigua del export (exp) teníamos una opción llamda CONSISTENT=Y que nos permitía congelar la base de datos en el momento del export de manera que, la exportacion de nuestra base de datos era totalmente consistente. Sin embargo, la nueva funcionalidad expdp no lo tiene ¿hemos dado un paso atrás?

Afortunadamente, la respuesta es no, lo único que pasa, es que (como siempre) Oracle nos ha puesto algo mas dificil acertar con el nombre.

Lo que haremos con el expdp será el hacer un expdp con la opción FLASHBACK_TIME ó FLASHBACK_SCN

La nueva sintaxsis será :

  • Para hacer un export en el momento 15-05-2014 a las 21:00
    expdp user/pass ... FLASHBACK_TIME="TO_TIMESTAMP('15-05-2014 21:00:00', 'DD-MM-YYYY HH24:MI:SS')" ...
    
  • Para hacer un export en el momento que lo lanzas
    expdp user/pass ... FLASHBACK_TIME=systimestamp  ...
    
  • O bien, para lanzar un export en un determinado SCN
    expdp user/pass ... FLASHBACK_SCN=7782903
    

Hay que tener en cuenta dos cosas cuando lanzamos un expdp con FLASHBACK

  • Las dos opciones TIME y SCN son excluyentes: No se pueden poner las dos claúsulas en el mismo script de export
  • Es necesario contar con un UNDO suficiente para albergar los datos durante todo el export: Lo que estamos haciendo con esto, es mantener la base de datos congelada en ese punto, si el export dura 7 horas, deberemos de contar con un UNDO capaz de mantener todos los datos que se llevan a cabo durante estas 7 horas, de lo contrario ,el export fallará con el error típico de UNDO insuficiente

Como siempre, la información completa en la Documentación de oracle

Tabla noexp$ en oracle

Hoy vamos ha hacer una de esas entradas «para guardar», su merito es totalmente de un compañero de trabajo, que me ha contado esta mañana la existencia de esta tabla.
Oracle tiene una tabla llamada noexp$ donde puedes ubicar los objetos de los que no quieras que se hagan exports.

Esta tabla tiene 3 campos, el OWNER del objeto, el OWNER del objeto y el tipo de objeto que es.

SQL> desc NOEXP$
Name Null? Type
--------------------- -------- ------------
 OWNER                 NOT NULL VARCHAR2(30)
NAME                  NOT NULL VARCHAR2(30)
OBJ_TYPE              NOT NULL NUMBER

Si queremos exportar la tabla PASS del esquema FOTOS, ejecutaremos el comando :

[oracle@test] [$expdp system/***** tables=FOTOS.PASS file=nada.dmp directory=backup
Export: Release 11.2.0.2.0 - Production on Lun Abr 14 16:38:48 2014
Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.
Connected to: Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
Legacy Mode Active due to the following parameters:
Legacy Mode Parameter: "file=nada.dmp" Location: Command Line, Replaced with: "dumpfile=nada.dmp"
Legacy Mode has set reuse_dumpfiles=true parameter.
Starting "SYSTEM"."SYS_EXPORT_TABLE_01":  system/******** tables=FOTOS.PASS dumpfile=nada.dmp directory=backup reuse_dumpfiles=true
Estimate in progress using BLOCKS method...
Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
Total estimation using BLOCKS method: 1024 KB
Processing object type TABLE_EXPORT/TABLE/TABLE
Processing object type TABLE_EXPORT/TABLE/INDEX/INDEX
Processing object type TABLE_EXPORT/TABLE/CONSTRAINT/CONSTRAINT
Processing object type TABLE_EXPORT/TABLE/INDEX/STATISTICS/INDEX_STATISTICS
Processing object type TABLE_EXPORT/TABLE/CONSTRAINT/REF_CONSTRAINT
Processing object type TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
. . exported "FOTOS"."PASS"                              6.796 KB      27 rows
Master table "SYSTEM"."SYS_EXPORT_TABLE_01" successfully loaded/unloaded
******************************************************************************
Dump file set for SYSTEM.SYS_EXPORT_TABLE_01 is:
  /vgbackup/backup/oracle/nada.dmp
Job "SYSTEM"."SYS_EXPORT_TABLE_01" successfully completed at 21:39:07

Ha funcionado correctamente, pero , y si no queremos que se pueda exportar esta tabla?

Lo primero que tendremos que hacer es ver el tipo de objeto que es esa tabla. Para ello ejecutaremos la consulta

SQL> select name,type# from obj$ where name = 'PASS';
NAME                                TYPE#
------------------------------ ----------
PASS                                    2

Una vez sabemos que es de tipo «2», la introduciremos en la tabla «noexp$» (como sys)

insert into NOEXP$ values ('FOTOS','PASS','2');

Que ocurre si intentas hacer un export de esa tabla??

[oracle@test [$expdp system/**** tables=FOTOS.PASS file=nada.dmp directory=backup
Export: Release 11.2.0.2.0 - Production on Lun Abr 14 16:42:03 2014
Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.
Connected to: Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
Legacy Mode Active due to the following parameters:
Legacy Mode Parameter: "file=nada.dmp" Location: Command Line, Replaced with: "dumpfile=nada.dmp"
Legacy Mode has set reuse_dumpfiles=true parameter.
Starting "SYSTEM"."SYS_EXPORT_TABLE_01":  system/******** tables=FOTOS.PASS dumpfile=nada.dmp directory=backup reuse_dumpfiles=true
Estimate in progress using BLOCKS method...
Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
Total estimation using BLOCKS method: 0 KB
ORA-39166: Object FOTOS.PASS was not found.
ORA-31655: no data or metadata objects selected for job
Job "SYSTEM"."SYS_EXPORT_TABLE_01" completed with 2 error(s) at 16:42:07

Como vemos, el export (expdp) no encuentra la tabla, con lo que no puede llevar a cabo la exportación.
Hay que tener mucho cuidado ya que, lo que no está exportando es la tabla, no los contenidos, con lo que , en nuestro caso, un export full de la base de datos haría que la aplicación no funcionase ya que ,no existe la tabla de passwords ( ni la estructura ni los datos)

Más información, como siempre en metalink en la nota «OERR: EXP 55 %s.%s is marked not exportable (Doc ID 47991.1)»

RMAN por entorno de red de windows (ORA-27040 )

Hoy veremos un error bastante comun cuando intentamos hacer un rman remoto en un entorno windows

Supongamos tenemos un servidor windows A y queremos hacer un backup de RMAN depositado en otro servidor windows B

rman target / nocatalog cmdfile rman_windows.cmd

Donde el fichero rman_windows.cmd es

run {
  allocate channel c1 type disk format '\\B\BCKORACLE\rman_pruebas%U';
  backup database;
}

En función de los permisos que tengamos en el servidor B, obtendremos un error:

canal c1: iniciando parte 1 en 18/08/13
canal liberado: c1
RMAN-00571: ===========================================================
RMAN-00569: =============== ERROR MESSAGE STACK FOLLOWS ===============
RMAN-00571: ===========================================================
RMAN-03009: fallo del comando backup en el canal c1 en 08/18/2013 09:12:55
ORA-19504: fallo al crear el archivo "\\B\BCKORACLE\rman_pruebas08OH_1"
ORA-27040: error de creacion de archivo, no se ha podido crear
OSD-04002: no se ha podido abrir el archivo
O/S-Error: (OS 5) Acceso denegado.
Recovery Manager terminado.

Como podemos ver en el error, leyendo siempre de abajo a arriba es un error de acceso de sistema operativo, tal y como indica la nota (Doc ID 145843.1) How to Configure RMAN to Write to Shared Drives on Windows NT/2000/2003 , Oracle necesita tener permisos de SYSTEM sobre el punto de red en el que va a escribir, por tanto tendremos que dar full control al usuario con el que se este ejecutando la base de datos ( o el script de lanzamiento) sobre el recurso remoto.

Un consejo para los windows 2003 en adelante es el no utilizar nombres locales de redes mapeadas, sino que es mas conveniente el uso de nombres de red genérico.

NOTA: En caso de ser una carpeta compartida por entorno de red de windows habrá que dar control total a el system de la máquina donde se ejecuta el Oracle, esto se puede haer con permisos a MI_DOMINIO\A$ donde MI_DOMINIO es el dominio y A el nombre del servidor

Detectando bloques corruptos en Oracle

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]