반응형
■ [2025-03-31] FlashBack Database가 ON인 상태에서 DROP USER CASCADE 작업 실수 발생 시 FlashBack Database로 유저 및 데이터가 존재했던 시점으로 돌아가서 exp로 데이터 덤프 후 복구하는 테스트 (12cR2)

<테스트 환경>

 

Oracle 12cR2 2 Node RAC

DB명 : DRDB

1번 노드 : DRDB1

2번 노드 : DRDB2

 

<테스트 개요>

 

DROP USER CASCADE 작업 실수 후 해당 DB에 플래시백 데이터베이스가 켜져있다면  Drop User 시점 이전으로 FLASHBACK DATABASE TO 명령을 통해 DB를 되돌린 후
READ ONLY 모드로 OPEN 하여 삭제 전 사용자(TUNER)의 데이터를 exp 유틸리티로 덤프 추출함 (read only mode이므로 expdp는 안됨)
DB를 RECOVER 후 READ/WRITE로 OPEN → 동일한 사용자 재생성 → imp를 이용해 데이터 복원 완료.

 

1. 아카이브 로그 모드 확인

 

[2025-03-30:22:34:01][rdb01d]<SYS@DRDB1> archive log list;
Database log mode              Archive Mode
Automatic archival             Enabled
Archive destination            +FRA1
Oldest online log sequence     21
Next log sequence to archive   22
Current log sequence           22

 

2. 플래시백 데이터베이스 설정

[2025-03-30:22:34:01][rdb01d]<SYS@DRDB1> SELECT FLASHBACK_ON FROM V$DATABASE;

FLASHBACK_ON
------------------------------------------------------
NO

1 row selected.

 

[2025-03-30:22:34:01][rdb01d]<SYS@DRDB1> ALTER DATABASE FLASHBACK ON;

[2025-03-30:22:34:01][rdb01d]<SYS@DRDB1> SELECT FLASHBACK_ON FROM V$DATABASE;

FLASHBACK_ON
------------------------------------------------------
YES

 

[2025-03-30:22:34:01][rdb01d]<SYS@DRDB1> show parameter db_flashback_retention_target;

NAME                                 TYPE                              VALUE
------------------------------------ --------------------------------- ------------------------------
db_flashback_retention_target        integer                           1440
--> 1440분 전까지 복구한 것을 목표로함

 

SELECT
    TO_CHAR(OLDEST_FLASHBACK_TIME, 'YYYY-MM-DD HH24:MI:SS') AS OLDEST_TIME,
    TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS') AS CURRENT_TIME
  FROM V$FLASHBACK_DATABASE_LOG;

OLDEST_TIME                                               CURRENT_TIME
--------------------------------------------------------- ---------------------------------------------------------
2025-03-30 22:34:58                                       2025-03-30 22:59:46

--> 해당 시점이 바로 아직 데이터가 존재하는 시점

 

3. 데이터 유실


[2025-03-31:22:26:57][rdb01d]<SYS@DRDB1>

col table_name for a50
SELECT TABLE_NAME FROM DBA_TABLES WHERE OWNER='TUNER';

TABLE_NAME
--------------------------------------------------
TB_CUST
TB_CUST_ADDR
TB_ORD
TB_DLVY
TB_ITEM
TB_ORD_DTL


[2025-03-31:22:26:57][rdb01d]<SYS@DRDB1> drop user tuner cascade;

--> 데이터가 유실된 상태

User dropped.

Elapsed: 00:06:59.71

 

[2025-03-31:22:26:57][rdb01d]<SYS@DRDB1> SELECT TABLE_NAME FROM DBA_TABLES WHERE OWNER= 'TUNER';

 

no rows selected


[2025-03-31:22:26:57][rdb01d]<SYS@DRDB1> quit
Disconnected from Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production

 

4. 플래시백 데이터베이스를 사용하여 데이터가 존재한 시점으로 돌아감

 

--전체 노드를 내린 후

[DRDB1:oracle@rdb01d][/home/oracle]$ srvctl stop database -db drdb

[DRDB1:oracle@rdb01d][/home/oracle]$ srvctl start instance -db drdb -node rdb01d -o mount

--> 1번 노드만 mount로 기동

 

[DRDB1:oracle@rdb01d][/home/oracle]$ csrctl stat res -t

ora.drdb.db
      1        ONLINE  INTERMEDIATE rdb01d                   Mounted (Closed),HOM
                                                             E=/u01/app/oracle/pr
                                                             oduct/12c/db_1,STABL
                                                             E
      2        OFFLINE OFFLINE                               Instance Shutdown,ST
                                                             ABLE

 

flashback database to timestamp to_date('2025-03-31:22:26:57','YYYY-MM-DD:HH24:MI:SS');

--> tuner 오너의 데이터가 있는 시점으로 돌아감 (다시 돌아올 것임)


[2025-03-31:22:43:05][rdb01d]<SYS@DRDB1> ALTER DATABASE OPEN READ ONLY;

--> read only 모드로 open

 

[DRDB1:oracle@rdb01d][/home/oracle]$ csrctl stat res -t
ora.drdb.db
      1        ONLINE  ONLINE       rdb01d                   Open,Readonly,HOME=/
                                                             u01/app/oracle/produ
                                                             ct/12c/db_1,STABLE
      2        OFFLINE OFFLINE                               Instance Shutdown,ST
                                                             ABLE

 

[2025-03-31:22:43:05][rdb01d]<SYS@DRDB1 > SELECT TABLE_NAME FROM DBA_TABLES WHEREOWNER= 'TUNER';

--> tuner 데이터가 있는 것을 확인

 

TABLE_NAME
---------------
TB_CUST
TB_CUST_ADDR
TB_ORD
TB_DLVY
TB_ITEM
TB_ORD_DTL

6 rows selected.

 

5. 유실된 데이터를 exp로 추출

 

exp owner=tuner file= tuner.dmp< /STRONG>

 

--> exp로 추출함 (expdp는 현재 read only mode라서 안됨 그러므로 exp로 추출함)

 

[DRDB1:oracle@rdb01d][/home/oracle]$ ls -alrt tuner.dmp
-rw-r--r--. 1 oracle oinstall 10772480 Mar 31 22:52 tuner.dmp

 

6. 다시 현재 상태로 돌아옴


[2025-03-31:22:57:39][rdb01d]<SYS@DRDB1> shutdown immediate;
[2025-03-31:22:57:39][rdb01d]<
SYS@DRDB1> startup mount

[2025-03-31:22:57:39][rdb01d]<SYS@DRDB1> recover database;

--export를 완료한 상태이기 때문에 복구후 다시 read/write open
Media recovery complete.

[2025-03-31:22:57:39][rdb01d]<SYS@DRDB1> alter database open;

--> read/write모드로 open (다시 현재 상태로 돌아온 것임)

 

7. 유실된 데이터를 추출한 5번 단계에서 추출한 덤프 파일로 복구

 

[2025-03-31:22:57:39][rdb01d]<SYS@DRDB1> create user tuner identified by oracle;

[2025-03-31:22:57:39][rdb01d]<SYS@DRDB1> grant connect,resource,dba to tuner;

--> tuner user를 생성하고 dba권한까지 줌


[DRDB1:oracle@rdb01d][/home/oracle]$ imp file=tuner.dmp fromuser= tuner TOUSER= tuner

--> import 시킴

 

8.유실된 데이터 복구 최종확인


[2025-03-31:23:04:48][rdb01d]<SYS@DRDB1 > SELECT TABLE_NAME FROM DBA_TABLES WHEREOWNER= 'TUNER';

 

TABLE_NAME
---------------
TB_ITEM
TB_ORD
TB_ORD_DTL
TB_CUST
TB_CUST_ADDR
TB_DLVY

 

SELECT /*+ PARALLEL(4) */
       A.*
  FROM
     (
        SELECT 'TUNER.TB_CUST' AS TABLE_NAME, COUNT(*) AS CNT FROM TUNER.TB_CUST A
        UNION ALL
        SELECT 'TUNER.TB_CUST_ADDR' AS TABLE_NAME, COUNT(*) AS CNT FROM TUNER.TB_CUST_ADDR A
        UNION ALL
        SELECT /*+ INDEX_FFS(A) */ 'TUNER.TB_DLVY' AS TABLE_NAME, COUNT(*) AS CNT FROM TUNER.TB_DLVY A
        UNION ALL
        SELECT 'TUNER.TB_ITEM' AS TABLE_NAME, COUNT(*) AS CNT FROM TUNER.TB_ITEM A
        UNION ALL
        SELECT 'TUNER.TB_ORD' AS TABLE_NAME, COUNT(*) AS CNT FROM TUNER.TB_ORD A
        UNION ALL
        SELECT /*+ INDEX_FFS(A) */ 'TUNER.TB_ORD_DTL' AS TABLE_NAME, COUNT(*) AS CNT FROM TUNER.TB_ORD_DTL A
    ) A
;

TABLE_NAME                                                    CNT
------------------------------------------------------ ----------
TUNER.TB_CUST                                                1000
TUNER.TB_CUST_ADDR                                           2000
TUNER.TB_DLVY                                               30000
TUNER.TB_ITEM                                                 100
TUNER.TB_ORD                                                10000
TUNER.TB_ORD_DTL                                            50000

--> tuner 사용자가 가지고 있었던 데이터가 정상적으로 복구됨 지금부터 다시 업무 진행하면됨

--> drop user cascade 후 플래시백이 켜진 상태라면 이러한 절차로 데이터를 복구 가능함

 

반응형

+ Recent posts