Use Recover Manager to Perform Complete Database Restore and Recovery Operations

1. Documentación en Tahiti -> Masters Book List -> Backup and Recovery User’s Guide -> 17 Performing Complete Database Recovery

Documentación en Tahiti -> Masters Book List -> Backup and Recovery User’s Guide -> 30 Performing User-Managed Recovery: Advanced Scenarios

2. Este es un objetivo crucial y no me refiero sólo al examen. Vamos a practicar distintos escenarios “desastre” en los que hemos perdido uno o varios archivos y tenemos que tener muy claro como poder recuperar la BD en todos los casos. Algún caso “extremo” conllevará perdida de información, pero también tenemos que saber como levantar la BD y dejarla operativa.

Esta es la lista de escenarios que vamos a practicar:

· Perdida de DATAFILE de SYSTEM
· Perdida de DATAFILE NO de SYSTEM
· Perdida de DATAFILE sin Backup
· Perdida de UN CONTROLFILE
· Perdida de TODOS los CONTROLFILE
· Perdida de ARCHIVELOG y REDOLOG
· Perdida de SPFILE, CONTROLFILE, DATAFILES y REDOLOGS

3. Comenzamos con el primer escenario. Vamos a borrar el DATAFILE 1, que pertenece al tablespace de SYSTEM y veamos como hay que realizar la recuperación. Antes de todo, aseguraros de que tenéis un Backup válido de la BD.

# Borramos el DATAFILE 1
rm /u01/app/oracle/oradata/OCM/system01.dbf

Aunque la BD se caerá antes o después, nosotros forzamos un ABORT para agilizar la operación.

-- Apagamos la BD
SHUTDOWN ABORT
STARTUP MOUNT
# Nos conectamos con rman a la BD y el catálogo</span>
<pre>rman target sys@ocm catalog rman/rman@oem

#Restauramos y recuperamos el DATAFILE
RESTORE DATAFILE 1;
RECOVER DATAFILE 1;
sql 'ALTER DATABASE OPEN';

4. ¿Qué sucede si perdemos un DATAFILE que no pertenece al tablespace SYSTEM? Muchisimo más fácil. Lo ponemos OFFLINE -> RESTORE DATAFILE -> RECOVER DATAFILE -> ONLINE. Pero en vez de hacerlo de la forma tradicional, vamos a usar una nueva funcionalidad que se llama Data Recovery Advisor (DRA) de la versión 11g. Esta realiza un diagnóstico del problema que está sucediendo y nos genera recomendaciones para solucionarlo.

# Borramos el DATAFILE del TABLESPACE USERS
rm /u01/app/oracle/oradata/OCM/users01.dbf
-- Forzamos el fallo intento escribir en el TBS
CREATE TABLE TEST (C1 NUMBER) TABLESPACE USERS;
# Nos conectamos con rman a la BD y el catálogo
rman target sys@ocm catalog rman/rman@oem

# Los comandos específicos de DRA se ejecutan dentro de RMAN
# Listamos el problema que hay en BD
LIST FAILURE;

# Analizamos el fallo para que DRA nos genere un script de correciones
ADVISE FAILURE;

# Vemos el contenido del script de reparación
REPAIR FAILURE PREVIEW;

# Ejecutamos el script
REPAIR FAILURE;

5. Una posible situación se puede dar cuando tenemos que recuperar un fichero en una ubicación distint a la original, porque se ha perdido (sí, esto sucede, para nuestra desgracia). Aunque también es fácil. Adjunto el script completo para realizarlo con el mismo DATAFILE del ejercicio anterior.

# Borramos el DATAFILE del TABLESPACE USERS
rm /u01/app/oracle/oradata/OCM/users01.dbf
-- Forzamos el fallo intento escribir en el TBS
CREATE TABLE TEST (C1 NUMBER) TABLESPACE USERS;
RUN {
  sql 'ALTER DATABASE DATAFILE 4 OFFLINE';
  SET NEWNAME FOR DATAFILE 4 TO '/u02/app/oracle/oradata/OCM/users01.dbf';
  RESTORE DATAFILE 4;
  SWITCH DATAFILE 4;
  RECOVER DATAFILE 4;
  sql 'ALTER DATABASE DATAFILE 4 ONLINE';
}

6. Si perdemos un DATAFILE y no tenemos Backup, aún podemos recuperar el DATAFILE. Las condiciones que debemos cumplir es que debemos tener todos los ARCHIVELOG desde que se creó dicho DATAFILE y además el nombre del DATAFILE está incluido en el CONTROLFILE. Podemos usar las técnicas anteriores, pero también tenemos esta posibilidad.

-- Creamos un TABLESPACE de prueba con una tabla de ejemplo
CREATE TABLESPACE TEST DATAFILE '/u01/app/oracle/oradata/OCM/test01.dbf' size 100M;
CREATE TABLE TEST_TABLE TABLESPACE TEST AS SELECT * FROM HR.EMPLOYEES;
# Borramos el DATAFILE
rm /u01/app/oracle/oradata/OCM/test01.dbf
-- Recuperamos el DATAFILE
ALTER DATABASE DATAFILE 6 OFFLINE;
-- Creamos un DATAFILE con las mismas características que el DATAFILE perdido
-- Podemos usar el mismo nombre para recuperar en la ubicación original o una distinta
ALTER DATABASE CREATE DATAFILE '/u01/app/oracle/oradata/OCM/test01.dbf' AS '/u02/app/oracle/oradata/OCM/test01.dbf';
RECOVER DATAFILE 6;
ALTER DATABASE DATAFILE 6 ONLINE;

-- Comprobamos que no hemos perdido datos
SELECT COUNT(*) FROM TEST_TABLE;

-- Limpiamos el entorno
DROP TABLESPACE TEST INCLUDING CONTENTS AND DATAFILES;

ALTER DATABASE CREATE DATAFILE '/u01/app/oracle/oradata/OCM/test01.dbf' AS '/u01/app/oracle/oradata/OCM/test01.dbf';

7. El siguiente escenario que quiero demostrar es la perdida de un CONTROLFILE. El procedimiento de recuperación consiste en copiar uno de los CONTROLFILE que tenemos en la máquina a la ubicación del que hemos perdido, y luego levantar la instancia. Ojo! Siempre hay que tener cuidado de no sobrescribir ningun CONTROLFILE, por si acaso. Antes de sobreescribir cualquier, lo copiamos o renombramos.

# Borramos un CONTROLFILE
rm /u01/app/oracle/oradata/OCM/control01.ctl
-- Cerramos la BD (si es que no se ha caido)
SHUTDOWN ABORT
# Copiamos el CONTROLFILE "vivo" en la ubicación del que hemos borrado
cp -p /u01/app/oracle/fast_recovery_area/OCM/control02.ctl /u01/app/oracle/oradata/OCM/control01.ctl
-- Levantamos la BD
STARTUP

8. Complicamos el ejercicio anterior, borrando todos los CONTROLFILE de la máquina.

# Borramos los dos CONTROLFILE que tenemos de la BD de OCM
rm /u01/app/oracle/oradata/OCM/control01.ctl
rm /u01/app/oracle/fast_recovery_area/OCM/control02.ctl
-- Cerramos la BD (si es que no se ha caido)
SHUTDOWN ABORT
# Ejecutamos el siguiente script desde RMAN
# Estos comandos se pueden ejecutando dentro de un bloque RUN, pero prefiero tener mayor control
STARTUP NOMOUNT;
RESTORE CONTROLFILE FROM AUTOBACKUP;
sql 'ALTER DATABASE MOUNT';
RECOVER DATABASE;
sql 'ALTER DATABASE OPEN RESETLOGS';

# Guardamos un BACKUP (IMPORTANTÍSIMO)
BACKUP AS COMPRESSED BACKUPSET DATABASE PLUS ARCHIVELOG;

9. Ahora supongo que hemos perdido los REDOLOG (todos) y los ARCHIVELOG. Esto significa que tenemos que recuperar la BD desde el último backup completo y luego aplicar todos los archivelogs que hayamos salvaguardado.

-- Lo primero es poner la BD en estado MOUNT
SHUTDOWN IMMEDIATE
STARTUP MOUNT

-- Obtenemos el último ARCHIVELOG aplicado para obtener la última secuencia (Ej)
--    THREAD# RESETLOGS_CHANGE# ARC  SEQUENCE# COMPLETIO
--- --------- ----------------- --- ---------- ---------
--          1           3012881 YES          2 07-JUN-13
SELECT
  THREAD#,
  RESETLOGS_CHANGE#,
  ARCHIVED,
  SEQUENCE#,
  COMPLETION_TIME
FROM
  V$ARCHIVED_LOG
WHERE
  ARCHIVED='YES'
  AND COMPLETION_TIME = (SELECT MAX(COMPLETION_TIME)
                         FROM V$ARCHIVED_LOG
                         WHERE ARCHIVED='YES');
# Dentro de RMAN, recuperamos la BD hasta el último ARCHIVELOG
# Si os fijáis, para que la BD recuperara hasta la SEQUENCE n (2), tenemos que indicar n+1 (3)
RESTORE DATABASE;
RECOVER DATABASE UNTIL SEQUENCE 3 THREAD 1;
sql 'ALTER DATABASE OPEN RESETLOGS';

# Guardamos un BACKUP (IMPORTANTÍSIMO)
BACKUP AS COMPRESSED BACKUPSET DATABASE PLUS ARCHIVELOG;

10. Entrenaremos ahora la perdida de SPFILE, CONTROLFILE, DATAFILES y REDOLOGS. Tenemos que recuperar el SPFILE/CONTROLFILE del AUTOBACKUP. Luego recuperaremos los DATAFILES y todos los ARCHIVELOGS que tengamos almacenados. Por último levantaremos la BD con RESETLOGS, ya que es una recuperación INCOMPLETA y la información que contiene no nos sirve.

# Borramos los ficheros
rm /u01/app/oracle/oradata/OCM/system01.dbf
rm /u01/app/oracle/oradata/OCM/sysaux01.dbf
rm /u01/app/oracle/oradata/OCM/undotbs01.dbf
rm /u02/app/oracle/oradata/OCM/users01.dbf
rm /u02/app/oracle/oradata/OCM/system02.dbf
rm /u01/app/oracle/oradata/OCM/temp01.dbf
rm /u01/app/oracle/oradata/OCM/control01.ctl
rm /u01/app/oracle/fast_recovery_area/OCM/control02.ctl
rm /u01/app/oracle/product/11.2.0/dbhome_1/dbs/spfileOCM.ora
rm /u01/app/oracle/oradata/OCM/redo101.log
rm /u01/app/oracle/oradata/OCM/redo201.log
rm /u01/app/oracle/oradata/OCM/redo301.log
rm /u02/app/oracle/oradata/OCM/redo102.log
rm /u02/app/oracle/oradata/OCM/redo202.log
rm /u02/app/oracle/oradata/OCM/redo302.log

# Tiramos la BD
SHUTDOWN ABORT

# Nos conectamos con RMAN
rman target sys@ocm catalog rman/rman@oem

# Fijamos el DBID de la BD
# Lo podemos obtener de los logs previos de RMAN o consultado el catálogo
#   Ej: connected to target database: OCM (DBID=2196200734)
#   Ej2: SELECT DB_ID FROM DB WHERE DB_KEY = (SELECT DB_KEY FROM DBINC
#                                             WHERE DB_NAME='OCM' AND DBINC_STATUS='CURRENT');
SET DBID 2196200734
-- Levantamos la instancia en modo NOMOUNT
STARTUP NOMOUNT

El primero paso es recuperar el SPFILE del AUTOBACKUP. Pero primero tenemos que configurar la FRA para que RMAN pueda encontrar el AUTOBACKUP sin problemas.

-- Configuramos los parámetros de la FRA
ALTER SYSTEM SET DB_RECOVERY_FILE_DEST_SIZE=4G;
ALTER SYSTEM SET DB_RECOVERY_FILE_DEST='/u01/app/oracle/fast_recovery_area';
# Recuperamos el SPFILE, reinciamos la instancia y restauramos la BD
RESTORE SPFILE FROM AUTOBACKUP;
SHUTDOWN IMMEDIATE;
STARTUP NOMOUNT;
RESTORE CONTROLFILE FROM AUTOBACKUP;
ALTER DATABASE MOUNT;
RESTORE DATABASE
-- Obtenemos el último ARCHIVELOG DISPONIBLE
SELECT
  THREAD#,
  RESETLOGS_CHANGE#,
  ARCHIVED,
  SEQUENCE#,
  COMPLETION_TIME
FROM
  V$ARCHIVED_LOG
WHERE
  ARCHIVED='YES'
  AND COMPLETION_TIME = (SELECT MAX(COMPLETION_TIME)
                         FROM V$ARCHIVED_LOG
                         WHERE ARCHIVED='YES');
# Recuperamos hasta el último ARCHIVELOG (n+1) y abrimos con RESETLOGS
RECOVER DATABASE UNTIL SEQUENCE 3 THREAD 1;
sql 'ALTER DATABASE OPEN RESETLOGS';

# Realizamos otro backup
BACKUP AS COMPRESSED BACKUPSET DATABASE PLUS ARCHIVELOG;

11. Simulamos la perdida del TABLESPACE temporal.

# Borramos el DATAFILE del tablespace temporal
rm /u01/app/oracle/oradata/OCM/temp01.dbf
-- Creamos un TABLESPACE temporal y lo asignamos por defecto a la BD
CREATE TEMPORARY TABLESPACE TEMP2 TEMPFILE '/u01/app/oracle/oradata/OCM/temp201.dbf' size 20M;
ALTER DATABASE DEFAULT TEMPORARY TABLESPACE TEMP2;

-- Recreamos el tablespace TEMP y lo asignamos por defecto a la BD
DROP TABLESPACE TEMP;
CREATE TEMPORARY TABLESPACE TEMP TEMPFILE '/u01/app/oracle/oradata/OCM/temp01.dbf' size 20M;
ALTER DATABASE DEFAULT TEMPORARY TABLESPACE TEMP;

-- Borramos el tablespace TEMP2 que hemos utilizado
-- Si no nos deja, tenemos que eliminar las sesiones que lo estén utilizando (la tuya propia, por ej.)
--   SELECT USERNAME, SESSION_NUM, SESSION_ADDR FROM V$SORT_USAGE;
DROP TABLESPACE TEMP2 INCLUDING CONTENTS AND DATAFILES;

12. Es posible, que infrecuente, que se produzca una corrupción de bloques en uno o varios ficheros de la BD. Si tenemos un backup válido de la BD y la tenemos en modo ARCHIVELOG no debería ser un problema. Vamos a simular una corrupción en un datafile de prueba y veremos cómo solucionarlo.

-- Creamos un TBS de prueba
CREATE TABLESPACE BC DATAFILE '/u01/app/oracle/oradata/OCM/bc01.dbf' SIZE 20M;

-- Creamos una tabla de ejemplo en dicho TBS
CREATE TABLE TEST_BC TABLESPACE BC AS SELECT * FROM DBA_OBJECTS;

-- Localizamos el Datafile (FILE_NO) y un bloque donde se almacena dicha tabla
-- En mi ejemplo obtengo esta salida:
--      FILE_NO   BLOCK_NO
--   ---------- ----------
--            5        131
SELECT DISTINCT
   MIN(DBMS_ROWID.ROWID_RELATIVE_FNO(rowid)) as FILE_NO,
   MIN(DBMS_ROWID.ROWID_BLOCK_NUMBER(rowid)) as BLOCK_NO
 FROM TEST_BC;

-- Limpiamos la caché (así forzamos que se muestre la corrupción rapidamente)
ALTER SYSTEM FLUSH BUFFER_CACHE;

Ahora debemos corromper dicho bloque con el comando ‘dd’ de Linux.

# Ejecutamos el comando dd dos veces para corromper el bloque que hemos localizado y el siguiente
# Lo importante es indicar el desplazamiento (SEEK = BLOCK_NO), en nuestro ejemplo seek=131
dd of=/u01/app/oracle/oradata/OCM/bc01.dbf bs=8192 conv=notrunc seek=131 << EOF
OCM ocm OCM ocm OCM ocm OCM ocm OCM ocm OCM ocm OCM ocm OCM ocm OCM ocm OCM ocm
EOF
dd of=/u01/app/oracle/oradata/OCM/bc01.dbf bs=8192 conv=notrunc seek=132 << EOF
OCM ocm OCM ocm OCM ocm OCM ocm OCM ocm OCM ocm OCM ocm OCM ocm OCM ocm OCM ocm
EOF
-- Forzamos la detección del bloque corrupto
-- Deben aparecer los errores ORA_01578 y ORA-01110
SELECT * FROM TEST_BC;

-- Podemos ver como se ha poblado la tabla V$DATABASE_BLOCK_CORRUPTION
SELECT * FROM V$DATABASE_BLOCK_CORRUPTION;

Vamos a utilizar DRA (Data Recovery Advisor) para recuperar estos bloques corruptos. Como ya lo hemos usado en ejercicios anteriores, vamos a hacerlo rapidamente.

# Nos conectamos con RMAN, listamos el fallo y obtenemos la recomendación de DRA
rman target / catalog rman/rman@OEM
LIST FAILURE;
ADVISE FAILURE;

# En otra sesión, vemos el contenido del fichero que se va a ejecutar para recuperar los bloques
# El contenido del script es el siguiente:
#   # block media recovery for multiple blocks
#   recover datafile 5 block 131 to 132;
cat /u01/app/oracle/diag/rdbms/ocm/OCM/hm/reco_3702026499.hm

# Lanzamos con RMAN el script de recuperación
REPAIR FAILURE;
-- Por último vamos a consultar de nuevo la tabla para ver si se ha corregido el problema.
SELECT * FROM TEST_BC;

-- Limpiamos el entorno
DROP TABLESPACE BC INCLUDING CONTENTS AND DATAFILES;