Hacer Flashback a Base de Datos Oracle con DataGuard

Introducción

A veces, en una aplicación que está usando la base Primaria de Oracle DataGuard, las cosas pueden salir mal y nos pedirán que recuperemos la base de datos a un punto previo en el tiempo. Si sólo han pasado algunas horas podemos evitar una recuperación larga con RMAN usando la funcionalidad de FLASHBACK.

Vamos a probar si podemos hacer flashback de la instancia Primaria a un punto de restauración previo y luego hacer lo mismo con la instancia Standby evitando reconstruirla.

Ambiente

Usaremos un ambiente DataGuard con una instancia Primaria y una Physical Standby en Oracle 19c con una base de datos pluggable.

Prerrequisitos

Primero necesitamos validar que ambas bases, Primaria y Standby tienen habilitado el flashback:

[oracle@patodgprmy ~]$ sqlplus / as sysdba

SQL*Plus: Release 19.0.0.0.0 - Production on Wed May 6 13:52:36 2020
Version 19.3.0.0.0

SQL> select name, database_role, flashback_on from v$database;

NAME      DATABASE_ROLE    FLASHBACK_ON
--------- ---------------- ------------------
PRMYDB    PRIMARY          YES
[oracle@patodgstby trace]$ sqlplus / as sysdba

SQL> select name, database_role, flashback_on from v$database;

NAME      DATABASE_ROLE    FLASHBACK_ON
--------- ---------------- ------------------
PRMYDB    PHYSICAL STANDBY YES

Preparar el Flashback

Crear un Punto de Restauración en la Primaria

Previo a la actividad que pudiera destruir los datos queremos configurar un punto de restauración al cual podremos regresar la base de datos:

[oracle@patodgprmy ~]$ sqlplus / as sysdba

SQL> create restore point FLASH_POINT GUARANTEE FLASHBACK DATABASE;

Restore point created.

Validar que la Replicación está Sincronizada

Última secuencia en la instancia Primaria:

[oracle@patodgprmy ~]$ sqlplus / as sysdba
SELECT ARCH.THREAD# Thread, ARCH.SEQUENCE# LastSequenceReceived, APPL.SEQUENCE# LastSequenceApplied, (ARCH.SEQUENCE# - APPL.SEQUENCE#) Difference FROM (SELECT THREAD# ,SEQUENCE# FROM V$ARCHIVED_LOG WHERE (THREAD#,FIRST_TIME ) IN (SELECT THREAD#,MAX(FIRST_TIME) FROM V$ARCHIVED_LOG GROUP BY THREAD#)) ARCH, (SELECT THREAD# ,SEQUENCE# FROM V$LOG_HISTORY WHERE (THREAD#,FIRST_TIME ) IN (SELECT THREAD#,MAX(FIRST_TIME) FROM V$LOG_HISTORY GROUP BY THREAD#)) APPL WHERE ARCH.THREAD# = APPL.THREAD# ORDER BY 1;

    THREAD LASTSEQUENCERECEIVED LASTSEQUENCEAPPLIED DIFFERENCE
---------- -------------------- ------------------- ----------
         1                    7                   7          0

Última secuencia en la instancia Standby:

[oracle@patodgstby ~]$ sqlplus / as sysdba
SELECT ARCH.THREAD# Thread, ARCH.SEQUENCE# LastSequenceReceived, APPL.SEQUENCE# LastSequenceApplied, (ARCH.SEQUENCE# - APPL.SEQUENCE#) Difference FROM (SELECT THREAD# ,SEQUENCE# FROM V$ARCHIVED_LOG WHERE (THREAD#,FIRST_TIME ) IN (SELECT THREAD#,MAX(FIRST_TIME) FROM V$ARCHIVED_LOG GROUP BY THREAD#)) ARCH, (SELECT THREAD# ,SEQUENCE# FROM V$LOG_HISTORY WHERE (THREAD#,FIRST_TIME ) IN (SELECT THREAD#,MAX(FIRST_TIME) FROM V$LOG_HISTORY GROUP BY THREAD#)) APPL WHERE ARCH.THREAD# = APPL.THREAD# ORDER BY 1;

    THREAD LASTSEQUENCERECEIVED LASTSEQUENCEAPPLIED DIFFERENCE
---------- -------------------- ------------------- ----------
         1                    7                   7          0

Perfecto, nuestras instancias están sincronizadas.

Destruir algunos Datos

En este ejemplo nuestro usuario se conectará a la base de datos pluggable y eliminará una tabla y borrará el contenido de una segunda tabla:

[oracle@patodgprmy ~]$ sqlplus /nolog

SQL> conn pato@taller;
Enter password:
Connected.
SQL> drop table t1 ;

Table dropped.

SQL> delete from t2 ;

5 rows deleted.

SQL> commit ;

Commit complete.

Validar los Datos Perdidos en la Standby

Deshabilitar la replicación y abrir la base Standby en modo lectura para validar:

[oracle@patodgstby ~]$ sqlplus / as sysdba

SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL;

Database altered.

SQL> alter database open read only;

Database altered.

SQL> ALTER PLUGGABLE DATABASE taller OPEN;

Pluggable database altered.

SQL> alter session set container = taller;

Session altered.

SQL> select count(*) from pato.t1 ;
select count(*) from pato.t1
                          *
ERROR at line 1:
ORA-00942: table or view does not exist

SQL> select count(*) from pato.t2 ;

  COUNT(*)
----------
         0

Sí, la tabla y los datos se perdieron también aquí. Habilitemos de nuevo la repliación y regresemos a la Primaria:

SQL> shutdown
Database closed.
Database dismounted.
ORACLE instance shut down.

SQL> startup mount
ORACLE instance started.

Total System Global Area 1610609888 bytes
Fixed Size                  9135328 bytes
Variable Size             956301312 bytes
Database Buffers          637534208 bytes
Redo Buffers                7639040 bytes
Database mounted.

SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT FROM SESSION;

Database altered.

Flashback DataGuard

Flashback en la Base de Datos Primaria

Valida que tengamos un punto de restauración y obtén el SCN para su uso posterior en la Standby:

[oracle@patodgprmy ~]$ sqlplus / as sysdba

SQL> select NAME, SCN from v$restore_point;

NAME                   SCN
--------------- ----------
FLASH_POINT        2990133

Necesitamos detener la instancia(shutdown) y luego montarla (startup mount) para poder ejecutar el flashback database y al final abriremos la base de datos con resetlogs.

SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.

SQL> startup mount
ORACLE instance started.

Total System Global Area 1610609888 bytes
Fixed Size                  9135328 bytes
Variable Size             989855744 bytes
Database Buffers          603979776 bytes
Redo Buffers                7639040 bytes
Database mounted.

SQL> flashback database to restore point FLASH_POINT;

Flashback complete.

SQL> alter database open resetlogs;

Database altered.

Validar los Datos Recuperados en la Base de Datos Primaria

[oracle@patodgprmy ~]$ sqlplus /nolog

SQL> conn pato@taller;
Enter password:
Connected.
SQL> select count(*) from t1;

  COUNT(*)
----------
         2

SQL> select count(*) from t2;

  COUNT(*)
----------
         5

Perfecto, la tabla y los datos fueron recuperados. Ahora creemos una nueva tabla para validar si la replicación está funcionando bien después de hacer flashback a la Standby:

SQL> create table t3 (i3 int, c3 varchar(20), d3 timestamp) ;

Table created.

SQL> insert into t3 values (1,'After flashback',current_timestamp);

1 row created.

SQL> commit ;

Commit complete.

Flashback en la Base de Datos Standby

Como los puntos de restauración no se replican, y tampoco configuramos un punto de restauración en la StandBy, vamos a regresar la base de datos a un SCN en particular. Del punto de restauración en la Primaria sabemos que necesitamos regresar al SCN 2990133, así que debemos validar si ese SCN está dentro del rango de flashback:

[oracle@patodgstby ~]$ sqlplus / as sysdba

SQL> select OLDEST_FLASHBACK_SCN from V$FLASHBACK_DATABASE_LOG;

OLDEST_FLASHBACK_SCN
--------------------
             2989744

Nuestro punto SCN del flashback deseado es mayor al más antiguo, así que estamos dentro del rango y podemos continuar.

Detengamos la replicación, hagamos el flashback de la Standby y habilitemos de nuevo la replicación:

SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL;

Database altered.

SQL> flashback standby database to SCN 2990133;

Flashback complete.

SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT FROM SESSION;

Database altered.

Validar los Datos Recuperados en la Base de Datos Standby

Démosle un tiempo a la Standby para que se sincronice y entonces cancelemos la recuperación y abramos la instancia en modo lectura:

[oracle@patodgstby ~]$ sqlplus / as sysdba

SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL;

Database altered.

SQL> alter database open read only;

Database altered.

SQL> ALTER PLUGGABLE DATABASE taller OPEN;

Pluggable database altered.

y entonces validemos:

SQL> alter session set container = taller;

Session altered.

SQL> select count(*) from pato.t1 ;

  COUNT(*)
----------
         2

SQL> select count(*) from pato.t2 ;

  COUNT(*)
----------
         5

SQL> select * from pato.t3 ;

        I3 C3                   D3
---------- -------------------- --------------------------------
         1 After flashback      06-MAY-20 02.25.41.879045 PM

Como podemos ver la tabla y los datos perdidos se recuperaron, pero también la nueva tabla generada después del flashback en la Primaria ha sido replicada.

Borrar el Punto de Restauración

No olvides borrar el punto de restauración usado para esta prueba:

[oracle@patodgprmy ~]$ sqlplus / as sysdba

SQL> DROP RESTORE POINT FLASH_POINT ;

Restore point dropped.

Conclusión

Como pudimos ver es posible realizar el flashback de las bases de datos (Primaria and Standby) pertenecientes a un ambiente DataGuard. Sólo nos tenemos que asegurar que ambas bases de datos tengan el flashback habilitado y que nuestro punto en el tiempo SCN esté dentro del rango disponible para hacer flashback.