프린트 하기

OS환경 : Oracle Linux 7.6 (64bit)

 

DB 환경 : Oracle Database 19.9.0.0

 

방법 : 오라클 DDL(drop 등)도 로그마이너로 복구가 될까?

DML 문(update, delete 문 등) 를 잘못 입력했을 때 로그마이너 v$logmnr_contents 의 sql_undo 컬럼으로 복구가 가능함

하지만 DDL 문을 잘못 입력한 경우 복구가 가능 한지 여부를 테스트하고자 함



사전 설정

로그마이너 설정

로그마이너가 있는지 확인

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
SQL> desc dbms_logmnr
PROCEDURE ADD_LOGFILE
 Argument Name            Type            In/Out Default?
 ------------------------------ ----------------------- ------ --------
 LOGFILENAME            VARCHAR2        IN
 OPTIONS            BINARY_INTEGER        IN     DEFAULT
FUNCTION COLUMN_PRESENT RETURNS BINARY_INTEGER
 Argument Name            Type            In/Out Default?
 ------------------------------ ----------------------- ------ --------
 SQL_REDO_UNDO            NUMBER            IN     DEFAULT
 COLUMN_NAME            VARCHAR2        IN     DEFAULT
PROCEDURE END_LOGMNR
FUNCTION MINE_VALUE RETURNS VARCHAR2
 Argument Name            Type            In/Out Default?
 ------------------------------ ----------------------- ------ --------
 SQL_REDO_UNDO            NUMBER            IN     DEFAULT
 COLUMN_NAME            VARCHAR2        IN     DEFAULT
PROCEDURE REMOVE_LOGFILE
 Argument Name            Type            In/Out Default?
 ------------------------------ ----------------------- ------ --------
 LOGFILENAME            VARCHAR2        IN
PROCEDURE START_LOGMNR
 Argument Name            Type            In/Out Default?
 ------------------------------ ----------------------- ------ --------
 STARTSCN            NUMBER            IN     DEFAULT
 ENDSCN             NUMBER            IN     DEFAULT
 STARTTIME            DATE            IN     DEFAULT
 ENDTIME            DATE            IN     DEFAULT
 DICTFILENAME            VARCHAR2        IN     DEFAULT
 OPTIONS            BINARY_INTEGER        IN     DEFAULT



default로 설치가 되어 있지 않다면 sysdba 유저로 설치 

1
SQL> @?/rdbms/admin/dbmslm.sql



supplemental logging 기능 상태 확인

1
2
3
4
5
SQL> select supplemental_log_data_min from v$database;
 
SUPPLEMENTAL_LOG
----------------
NO

 


supplemental logging 기능 활성화

1
2
3
SQL> alter database add supplemental log data;
 
Database altered.



supplemental logging 기능 상태 재확인

1
2
3
4
5
SQL> select supplemental_log_data_min from v$database;
 
SUPPLEMENTAL_LOG
----------------
YES



시나리오

샘플 유저 생성 및 권한 부여

1
2
3
4
5
6
7
SQL> create user new identified by new account unlock default tablespace users quota unlimited on users;
 
User created.
 
SQL> grant resource, connect, dba to new;
 
Grant succeeded.



로그마이너 사용시 찾는 시간이 오래 걸리기때문에 

특정 로그파일에서만 작업을 하고 그 로그파일만 로그마이너를 이용하여 읽을 예정

리두로그 확인

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
SQL> 
set lines 200
set pages 1000
col member for a60
select l.group#, member, archived, l.status, (bytes/1024/1024) MB
from v$log l, v$logfile f
where f.group# = l.group#
order by 1
/
 
    GROUP# MEMBER                            ARC STATUS             MB
---------- ------------------------------------------------------------ --- ---------------- ----------
     1 /app/oracle/oradata/ORCL19/redo01.log            YES INACTIVE           1024
     2 /app/oracle/oradata/ORCL19/redo02.log            YES INACTIVE           1024
     3 /app/oracle/oradata/ORCL19/redo03.log            NO  CURRENT           1024

현재 3번 redo 가 current 상태임



모두 아카이브로 내려씀

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
SQL> 
SQL> alter system checkpoint;
 
System altered.
 
SQL> alter system switch logfile;
 
System altered.
 
SQL> /
 
System altered.
 
SQL> /
 
System altered.
 
SQL> /
 
System altered.



다시 리두로그 확인

1
2
3
4
5
6
7
8
9
10
11
12
13
14
SQL> 
set pages 1000
col member for a60
select l.group#, member, archived, l.status, (bytes/1024/1024) MB
from v$log l, v$logfile f
where f.group# = l.group#
order by 1
/
 
    GROUP# MEMBER                            ARC STATUS             MB
---------- ------------------------------------------------------------ --- ---------------- ----------
     1 /app/oracle/oradata/ORCL19/redo01.log            YES INACTIVE           1024
     2 /app/oracle/oradata/ORCL19/redo02.log            NO  CURRENT           1024
     3 /app/oracle/oradata/ORCL19/redo03.log            YES INACTIVE           1024

2번 redo가 current 가 됨



샘플 테이블 생성

1
2
3
4
5
6
7
8
9
SQL> create table ddl_table as select * from dba_objects;
 
Table created.
 
SQL> select count(*from ddl_table;
 
  COUNT(*)
----------
     23866



샘플 테이블 업데이트 및 삭제

1
2
3
4
5
6
7
8
9
10
11
SQL> update ddl_table set object_id = 0;
 
23866 rows updated.
 
SQL> commit;
 
Commit complete.
 
SQL> drop table ddl_table;
 
Table dropped.



현재 리두로그 확인

1
2
3
4
5
6
7
8
9
10
11
12
13
14
SQL>
set pages 1000
col member for a60
select l.group#, member, archived, l.status, (bytes/1024/1024) MB
from v$log l, v$logfile f
where f.group# = l.group#
order by 1
/
 
    GROUP# MEMBER                            ARC STATUS             MB
---------- ------------------------------------------------------------ --- ---------------- ----------
     1 /app/oracle/oradata/ORCL19/redo01.log            YES INACTIVE           1024
     2 /app/oracle/oradata/ORCL19/redo02.log            NO  CURRENT           1024
     3 /app/oracle/oradata/ORCL19/redo03.log            YES INACTIVE           1024

계속 2번 redo 가 current임



로그마이너 사용

디렉토리 생성

1
2
3
4
5
SQL> !mkdir -/home/oracle/logmnr
 
SQL> create directory dict as '/home/oracle/logmnr';
 
Directory created.



딕셔너리 파일 생성

1
2
3
4
5
6
7
8
9
SQL>
BEGIN 
       SYS.DBMS_LOGMNR_D.build ( 
       dictionary_filename => 'logmnrdict.ora'
       dictionary_location => 'DICT');  --디렉토리 이름 대문자로 입력
END;
/
 
PL/SQL procedure successfully completed.



파일 생성 확인

1
2
3
4
5
SQL> !ls -al /home/oracle/logmnr
total 24068
drwxr-xr-x  2 oracle dba       46 Jan 31 21:48 .
drwx------. 3 oracle dba       73 Jan 31 21:29 ..
-rw-r--r--  1 oracle dba 24639488 Jan 31 22:03 logmnrdict.ora



분석 할 로그 파일을 등록(현재 current인 redo 2번)

1
2
3
SQL> exec dbms_logmnr.add_logfile('/app/oracle/oradata/ORCL19/redo02.log',1);
 
PL/SQL procedure successfully completed.



등록한 log 파일을 분석

1
2
3
SQL> exec dbms_logmnr.start_logmnr(dictfilename=>'/home/oracle/logmnr/logmnrdict.ora');
 
PL/SQL procedure successfully completed.



로그마이너 update 문 조회

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
SQL>
set line 200
col timestamp for a20
col seg_owner for a10
col username for a10
col sql_redo for a120
col sql_undo for a120
select to_char(timestamp,'YYYY-MM-DD:HH24:MI:SS') time, seg_owner, username, sql_redo, sql_undo
from v$logmnr_contents
where sql_redo like '%update%'
and seg_owner='NEW';
 
 
TIME               SEG_OWNER   USERNAME   SQL_REDO
------------------- ---------- ---------- ------------------------------------------------------------------------------------------------------------------------
SQL_UNDO
------------------------------------------------------------------------------------------------------------------------
2021-01-31:21:56:55 NEW         NEW       update "NEW"."BIN$ujLHb7HffCLgU/AKqMBQ1w==$0" 
                                          set "COL 4" = HEXTORAW('80'
                                          where "COL 4" = HEXTORAW('c113'
                                          and ROWID = 'AAANJiAAEAAAFqDAAA';
update "NEW"."BIN$ujLHb7HffCLgU/AKqMBQ1w==$0" 
set "COL 4" = HEXTORAW('c113'
where "COL 4" = HEXTORAW('80'
and ROWID = 'AAANJiAAEAAAFqDAAA';
 
2021-01-31:21:56:55 NEW         NEW       update "NEW"."BIN$ujLHb7HffCLgU/AKqMBQ1w==$0" 
                                          set "COL 4" = HEXTORAW('80'
                                          where "COL 4" = HEXTORAW('c121'
                                          and ROWID = 'AAANJiAAEAAAFqDAAB';
update "NEW"."BIN$ujLHb7HffCLgU/AKqMBQ1w==$0" 
set "COL 4" = HEXTORAW('c121'
where "COL 4" = HEXTORAW('80'
and ROWID = 'AAANJiAAEAAAFqDAAB';
.
.

현재 테이블을 drop 한 상태로 recyclebin에 있는 이름(BIN$~)로 표시됨

내가 입력한 update 구문인 sql_redo 와 그 update 구문을 복구할 구문(sql_undo) 두가지가 모두 나옴



로그마이너 drop 문 조회

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
SQL>
set line 200
col timestamp for a20
col seg_owner for a10
col username for a10
col sql_redo for a120
col sql_undo for a120
select to_char(timestamp,'YYYY-MM-DD:HH24:MI:SS') time, seg_owner, username, sql_redo, sql_undo
from v$logmnr_contents
where sql_redo like '%drop%'
and seg_owner='NEW';
 
TIME            SEG_OWNER  USERNAME   SQL_REDO
------------------- ---------- ---------- ------------------------------------------------------------------------------------------------------------------------
SQL_UNDO
------------------------------------------------------------------------------------------------------------------------
2021-01-31:21:57:25 NEW        NEW      drop table ddl_table AS "BIN$ujLHb7HffCLgU/AKqMBQ1w==$0" ;

drop 문의 경우 시간과 sql_redo는 나오지만 sql_undo(복구구문)은 나오지 않음

drop 구문은 로그마이너로 복구 불가능



recyclebin 에서 복구

1
2
3
SQL> flashback table ddl_table to before drop;
 
Flashback complete.



테이블 확인

1
2
3
4
5
SQL> select count(*from ddl_table;
 
  COUNT(*)
----------
     23866



결론 : ddl drop 구문은 로그마이너로 복구가 불가능함

하지만 flashback 기능 이용하거나 해당 테이블 생성 이전 시점으로 가서 복구하는

Point In Time Recovery (PITR)을 통해 복구는 가능함



참조 : https://positivemh.tistory.com/424

https://positivemh.tistory.com/284