Flashback Oracle DataGuard Database

Introduction

Sometimes, in an application that is using an Oracle DataGuard Primary database, things may go wrong and we will be requested to rollback the database to a previous point in time. If only few hour has passed, we may avoid an RMAN long recovery by using the FLASHBACK functionality.

We are going to test if we can flashback the Primary instance to a previous restore point and do the same with the Standby instance to avoid rebuilding it.

Environment

We are using a DataGuard environment with a Primary instance and one Physical Standby on Oracle 19c with one pluggable database.

Prerequisites

First we need to validate both Primary and Standby has flashback turned on:

[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

Preparing Flashback

Create Restore Point in Primary

Before the activity that may destroy the data we want to setup a safe point to which we may flashback the database:

[oracle@patodgprmy ~]$ sqlplus / as sysdba

SQL> create restore point FLASH_POINT GUARANTEE FLASHBACK DATABASE;

Restore point created.

Validate Replication is in Sync

Last sequence in Primary instance:

[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

Last sequence in Standby instance:

[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

OK our instances are in sync.

Destroy some Data

In this example our user will connect to the pluggable database and drop one table and delete the contents of a second table:

[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.

Validate Data is Lost in Standby

Disable replication and open the Standby in read only mode to validate:

[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

Yes the table and data are gone also here. Let’s reenable replication and go back to Primary:

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 Primary Database

Validate we have a restore point and get the SCN for later use in Standby:

[oracle@patodgprmy ~]$ sqlplus / as sysdba

SQL> select NAME, SCN from v$restore_point;

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

We need to shutdown the instance, then startup mount in order to be able to flashback database and then we will open the database with 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.

Validate Data is Back on Primary Database

[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

OK the table and data were recovered. Now let’s create a new table to later check if replication is working ok after we flashback the 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 Standby Database

As restore points are not replicated, neither we setup a restore point in the Standby, we are going to flashback to a particular SCN. From Primary restore point we know we need to go back to SCN 2990133, so we need to validate if that SCN is within flashback range:

[oracle@patodgstby ~]$ sqlplus / as sysdba

SQL> select OLDEST_FLASHBACK_SCN from V$FLASHBACK_DATABASE_LOG;

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

Our desired flashback point SCN is greater than the oldest, so we are within the range and can continue.

Stop the replication, flashback the Standby and reenable recovery:

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.

Validate Data is Recovered in Standby

Let’s give a time for the Standby to resync and then cancel recovery and open the instance in read only:

[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.

then we validate:

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

As we can see the lost table and data are recovered, but also the new table generated after Primary flashback has been replicated as well.

Cleanup

Don’t forget to drop the restore point used for this test:

[oracle@patodgprmy ~]$ sqlplus / as sysdba

SQL> DROP RESTORE POINT FLASH_POINT ;

Restore point dropped.

Conclusion

As we can see it is possible to flashback the databases (Primary and Standby) belonging to a Data Guard environment. We just need to ensure both databases has flashback turned on and that our SCN point in time is within the available flashback range.