본문 바로가기

DB/__Oracle

[펌] 오라클 log miner의 활용

log miner의 활용

실수로 데이터를 삭제한 것을, 오라클에서는 user error라고 하여 에러종류중 하나로 취급한다.
밑에서 언급되는 삭제된 데이터는 user error에 인한 것으로 묵시적으로 취급할 것이다.
로그마이너는 대충 다음과 같은 기능을 수행할 수 있다.

테이블 데이터를 delete한 사용자 파악
삭제한 데이터를 검출하여 복구
DML문장을 수행한 사용자와 실행된 순서 파악
활동이 많은 테이블(디스크 액세스 분석정보) 파악


[예제]
아래의 파라메터를 확인하여 비어있는경우 지정해준다
utl_file_dir=C:oracleoradatawork
alter system set utl_file_dir='C:oracleoradatawork' deferred scope=spfile;
이와같이 한 후 오라클을 다시기동시키면 적용됨

SQL> connect sys
연결되었습니다.
SQL> @?/rdbms/admin/dbmslm.sql

패키지가 생성되었습니다.


권한이 부여되었습니다.

dbmslmd.sql파일의 varchar2(513)인 컬럼을 varchar2(1000)으로 변경한 다음, 실행
SQL> @?/rdbms/admin/dbmslmd.sql

패키지가 생성되었습니다.


패키지 본체가 생성되었습니다.

오류가 없음.

권한이 부여되었습니다.




[일반유저에서 테스트할 DML을 수행]

SQL> create table test ( id varchar(10), name varchar(10));

테이블이 생성되었습니다.

SQL> insert into test values('maddog', '강명규');

1 개의 행이 만들어졌습니다.

SQL> insert into test values('superman', '슈퍼맨');

1 개의 행이 만들어졌습니다.

SQL> commit;

커밋이 완료되었습니다.

SQL>


[다시 sys유저에서]
이미 logmnr_dic.ora파일이 존재한다면 EOF에러가 발생하므로, 먼저 삭제한 다음 해야한다.
그리고, 분석할 객체(테이블,.. 여기서는 kang의 test테이블이 될 것이다.)를 먼저 생성한 후 실행해주는 것이 좋다.
아니면, v_logmnr_contents의 seg_name, seg_type컬럼값이 표시되지 않는다.

SQL> exec dbms_logmnr_d.build('logmnr_dic.ora', 'C:oracleoradatawork');

SQL> select member from v$logfile;

MEMBER
--------------------------------------------------------------------------------
C:ORACLEORADATAMADDOGREDO01.LOG
C:ORACLEORADATAMADDOGREDO02.LOG
C:ORACLEORADATAMADDOGREDO03.LOG

SQL> exec dbms_logmnr.add_logfile('C:ORACLEORADATAMADDOGREDO01.LOG', dbms_logmnr.NEW);

PL/SQL 처리가 정상적으로 완료되었습니다.

SQL> exec dbms_logmnr.add_logfile('C:ORACLEORADATAMADDOGREDO02.log', dbms_logmnr.ADDFILE);

PL/SQL 처리가 정상적으로 완료되었습니다.

SQL> exec dbms_logmnr.add_logfile('C:ORACLEORADATAMADDOGREDO03.log', dbms_logmnr.ADDFILE);

PL/SQL 처리가 정상적으로 완료되었습니다.

SQL> exec dbms_logmnr.start_logmnr(dictfilename=> 'C:oracleoradataworklogmnr_dic.ora');

PL/SQL 처리가 정상적으로 완료되었습니다.


이제, kang에서 insert한 작업에 대한 것을 v$logmnr_contents뷰를 통해 알아보자.

SQL> set linesize 200
SQL> col operation format a10
SQL> col sql_redo format a40
SQL> col sql_undo format a40

SQL> select operation, sql_redo, sql_undo
2 from v$logmnr_contents
3 where
4 seg_owner='KANG' and seg_name='TEST' and
5 operation='INSERT' and username='KANG';

OPERATION SQL_REDO SQL_UNDO
---------- ---------------------------------------- ----------------------------------------
INSERT insert into "KANG"."TEST"("ID","NAME") v delete from "KANG"."TEST" where "ID" = '
alues ('maddog','강명규'); maddog' and "NAME" = '강명규' and ROWID
= 'AAAAxnAADAAAAADAAA';

INSERT insert into "KANG"."TEST"("ID","NAME") v delete from "KANG"."TEST" where "ID" = '
alues ('superman','슈퍼맨'); superman' and "NAME" = '슈퍼맨' and ROWI
D = 'AAAAxnAADAAAAADAAB';

테이블 소유자가 KANG이고, 테이블명이 TEST, KANG이란 유저가 INSERT한 레코드를 찾는 것이다.
SQL_REDO에서는 작업한 내용이 표시되고, SQL_UNDO에는 취소할 수 있는 SQL문이 표시된다.
즉, SQL_REDO와 대응되는 SQL_UNDO는 실행한 작업을 되돌릴 수 있게 한다.
위에서는 ROWID가 ROW를 식별하기 위한 조건으로 표시되고 있는데, 실제 ROWID를 확인해 보자.

[KANG유저에서 실행]
SQL> SELECT ROWID, TEST.* FROM TEST;

ROWID ID NAME
------------------ ---------- ----------
AAAAxnAADAAAAADAAA maddog 강명규
AAAAxnAADAAAAADAAB superman 슈퍼맨



그럼, 실수로 테이블데이터를 삭제했을때의 시나리오를 생각해 보자.

[KANG유저에서 실행]
SQL> delete from test;

2 행이 삭제되었습니다.

SQL> commit;

커밋이 완료되었습니다.



위에서 test에 있는 모든 데이터를 삭제했고, commit까지 했다.
어떻게 복구할 것인가?
v_logmnr_contents뷰에서 delete operation을 검색하여 나온 row의 sql_undo컬럼값으로 실행하면 될 것이다.

SQL> select operation, sql_redo, sql_undo
2 from v$logmnr_contents
3 where
4 seg_owner='KANG' and seg_name='TEST' and
5 operation='DELETE' and username='KANG';

OPERATION SQL_REDO SQL_UNDO
---------- ---------------------------------------- ----------------------------------------
DELETE delete from "KANG"."TEST" where "ID" = ' insert into "KANG"."TEST"("ID","NAME") v
maddog' and "NAME" = '강명규' and ROWID alues ('maddog','강명규');
= 'AAAAxnAADAAAAADAAA';

DELETE delete from "KANG"."TEST" where "ID" = ' insert into "KANG"."TEST"("ID","NAME") v
superman' and "NAME" = '슈퍼맨' and ROWI alues ('superman','슈퍼맨');
D = 'AAAAxnAADAAAAADAAB';



sql_undo컬럼값을 수행해 주자.
복구끝.

SQL> insert into "KANG"."TEST"("ID","NAME") values ('maddog','강명규');

1 개의 행이 만들어졌습니다.

SQL> insert into "KANG"."TEST"("ID","NAME") values ('superman','슈퍼맨');

1 개의 행이 만들어졌습니다.

SQL> commit;

커밋이 완료되었습니다.

SQL> select * from kang.test;

ID NAME
---------- ----------
superman 슈퍼맨
maddog 강명규

SQL>

This article comes from dbakorea.pe.kr (Leave this line as is)