()

Recover a Table from Drop/Truncate/Delete done on Primary using Flashback on a Standby


In this article, we will learn steps needed to perform recovery of User wrong operation like delete/drop/truncate action on the production table without using Restore and Recover command on PRIMARY DATABASE.
Recovering the table from the standby database will also eliminate any required downtime on the primary database.
For this, you should have an up and running Standby database with Flashback On feature.
Please note the
time when Drop/Truncate/Delete operation happened should be within the db_flashback_retention_target and all the flashback and archive logs should be available. Below is step by step recover a table.

First, perform the below commands on PRIMARY DATABASE.

SQL> set lines 300
SQL> col name for a10
SQL> select NAME,DATABASE_ROLE,OPEN_MODE,LOG_MODE,FLASHBACK_ON,FORCE_LOGGING,PROTECTION_MODE,PROTECTION_LEVEL,SWITCHOVER_STATUS from v$database;

NAME       DATABASE_ROLE    OPEN_MODE            LOG_MODE     FLASHBACK_ON       FOR PROTECTION_MODE      PROTECTION_LEVEL     SWITCHOVER_STATUS
---------- ---------------- -------------------- ------------ ------------------ --- -------------------- -------------------- --------------------
PROD01       PRIMARY          READ WRITE           ARCHIVELOG   NO                 YES MAXIMUM PERFORMANCE  MAXIMUM PERFORMANCE  SESSIONS ACTIVE


Execute the below commands on STANDBY DATABASE.

SQL> show parameter db_recovery

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
db_recovery_file_dest                string      M:\FLASH_RECOVERY_AREA
db_recovery_file_dest_size           big integer 80G

SQL> show parameter retention

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
db_flashback_retention_target        integer     7200
undo_retention                       integer     86400

SQL> set lines 300
SQL> col name for a10
SQL> select NAME,DATABASE_ROLE,OPEN_MODE,LOG_MODE,FLASHBACK_ON,FORCE_LOGGING,PROTECTION_MODE,PROTECTION_LEVEL,SWITCHOVER_STATUS from v$database;

NAME       DATABASE_ROLE    OPEN_MODE            LOG_MODE     FLASHBACK_ON       FOR PROTECTION_MODE      PROTECTION_LEVEL     SWITCHOVER_STATUS
---------- ---------------- -------------------- ------------ ------------------ --- -------------------- -------------------- --------------------
PROD01       PHYSICAL STANDBY READ ONLY WITH APPLY ARCHIVELOG   YES                YES MAXIMUM PERFORMANCE  MAXIMUM PERFORMANCE  NOT ALLOWED


SQL> set lines 200
SQL> set pages 200
SQL> select inst_id,process,status,client_process,THREAD#,sequence#,block#,active_agents,known_agents from gv$managed_standby where PROCESS like 'MRP%' or client_process like 'LGWR';

   INST_ID PROCESS   STATUS       CLIENT_P    THREAD#  SEQUENCE#     BLOCK# ACTIVE_AGENTS KNOWN_AGENTS
---------- --------- ------------ -------- ---------- ---------- ---------- ------------- ------------
         1 RFS       IDLE         LGWR              1        806     343899             0            0
         1 MRP0      APPLYING_LOG N/A               1        806     343898            33           33


Suppose in PRIMARY DATABASE developer by mistake truncate table TEST_RECOVERY on “21-dec-20 10:50:08” and approach DBA to recover the table, So you can follow the below steps on the STANDBY DATABASE to recover the truncated table. Please note while doing flashback on STANDBY DATABASE, we went back in time by 1 min ‘21-dec-20 10:49:00‘.

Execute the below commands on PRIMARY DATABASE where we truncate table TEST_RECOVERY.

SQL> select count(*) from test_recovery;

  COUNT(*)
----------
       100
	   
SQL> truncate table test_recovery;

Table truncated.

SQL> select to_char(sysdate,'dd-mon-yy hh24:mi:ss') from dual;

TO_CHAR(SYSDATE,'DD-MON-YYH
---------------------------
21-dec-20 10:50:08


Execute all commands in STANDBY DATABASE.

SQL> alter database recover managed standby database cancel;

Database altered.


SQL> create restore point flashback_point guarantee flashback database;

Restore point created.


SQL> col name for a50
SQL> set lines 300
SQL> select name, to_char(scn), time from v$restore_point;

NAME                                               TO_CHAR(SCN)                             TIME
-------------------------------------------------- ---------------------------------------- ---------------------------------------------------------------------------
FLASHBACK_POINT                                    13610647843                              21-DEC-20 10.53.02.000000000 AM


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


SQL>  startup mount
ORACLE instance started.

Total System Global Area 4275781632 bytes
Fixed Size                  2288096 bytes
Variable Size            1509951008 bytes
Database Buffers         2751463424 bytes
Redo Buffers               12079104 bytes
Database mounted.


SQL>  flashback database to timestamp TO_TIMESTAMP( '2020-12-21 10:49:00','YYYY-MM-DD HH24:MI:SS');

Flashback complete.

SQL>  alter database activate standby database;

Database altered.


SQL>  select controlfile_type from v$database;

CONTROL
-------
CURRENT


SQL> select status from v$instance;

STATUS
------------
MOUNTED


SQL> alter database open;

Database altered.


SQL> select count(*) from test_recovery;

  COUNT(*)
----------
       100


Please use EXPDP utility to take a backup of table TEST_RECOVERY from STANDBY DATABASE and import in PRIMARY DATABASE, Once export-import is done follow the below steps to convert DB to Standby, all commands in STANDBY DATABASE.

SQL>  startup mount force;
ORACLE instance started.

Total System Global Area 4275781632 bytes
Fixed Size                  2288096 bytes
Variable Size            1509951008 bytes
Database Buffers         2751463424 bytes
Redo Buffers               12079104 bytes
Database mounted.


SQL>  flashback database to restore point flashback_point;

Flashback complete.  
SQL>  alter database convert to physical standby;

Database altered.


SQL>  startup mount force;
ORACLE instance started.

Total System Global Area 4275781632 bytes
Fixed Size                  2288096 bytes
Variable Size            1509951008 bytes
Database Buffers         2751463424 bytes
Redo Buffers               12079104 bytes
Database mounted.


SQL> select controlfile_type from v$database;

CONTROL
-------
STANDBY


SQL>  drop restore point flashback_point;

Restore point dropped.


SQL> alter database open;

Database altered.


SQL> alter database recover managed standby database using current logfile disconnect from session;

Database altered.


SQL> set lines 200
SQL> set pages 200
SQL> select inst_id,process,status,client_process,THREAD#,sequence#,block#,active_agents,known_agents from gv$managed_standby where PROCESS like 'MRP%' or client_process like 'LGWR';

   INST_ID PROCESS   STATUS       CLIENT_P    THREAD#  SEQUENCE#     BLOCK# ACTIVE_AGENTS KNOWN_AGENTS
---------- --------- ------------ -------- ---------- ---------- ---------- ------------- ------------
         1 RFS       IDLE         LGWR              1        809        530             0            0
         1 MRP0      APPLYING_LOG N/A               1        809        529            33           33


SQL> /

   INST_ID PROCESS   STATUS       CLIENT_P    THREAD#  SEQUENCE#     BLOCK# ACTIVE_AGENTS KNOWN_AGENTS
---------- --------- ------------ -------- ---------- ---------- ---------- ------------- ------------
         1 RFS       IDLE         LGWR              1        809        534             0            0
         1 MRP0      APPLYING_LOG N/A               1        809        533            33           33

In this final step, we just validate the row count of a table in PRIMARY DATABASE.

SQL> select count(*) from test_recovery;

  COUNT(*)
----------
       100
	   

SQL> select to_char(sysdate,'dd-mon-yy hh24:mi:ss') from dual;

TO_CHAR(SYSDATE,'DD-MON-YYH
---------------------------
21-dec-20 11:38:17


This document is only for learning purpose and always validate in the LAB environment first before applying in the LIVE environment.


Hope so you like this article!
Please share your valuable feedback/comments/subscribe and follow us below and don’t forget to click on the bell icon to get the most recent update. Click here to understand more about our pursuit.

Loading

How useful was this post?

Click on a star to rate it!

Average rating / 5. Vote count:

No votes so far! Be the first to rate this post.

As you found this post useful...

Follow us on social media!

We are sorry that this post was not useful for you!

Let us improve this post!

Tell us how we can improve this post?

Jamsher Khan

Hello and welcome to DBsGuru,I’m Jamsher Khan working as Senior Oracle DBA based in KSA-Jeddah, I have working experience in Oracle DBA, SQL Server, MySql, PostgreSQL, Linux, Golden Gate, ODA.Thanks for the visits!Share Learn Grow!