# Soft parsing step
1. 사용자가 새로운 SQL 문장 수행 요청
2. 기본적인 문법체크와 권한체크 등을 수행
3. 해쉬 버켓을 관리하는 라이브러리 캐시 래치를 획득
4. 라이브러리 캐시 영역에 동일한 SQL문장, 즉 동일한 LCO가 존재하는지 확인
5. 라이브러리 캐시 래치를 획득하는 과정에서 경합이 발생하면 latch:library cache 이벤트를 대기
6. 동일한 LCO가 존재하는 경우에는 SQL 커서에 대해 library cache Lock과 라이브러리 캐시 Pin을 shared mode로 획득하고 SQL 문장을 실행
cf) SQL 커서가 참조하는 LCO에 대해서는 기본적으로 SQL 커서와 동일한 모드로 라이브러리 캐시 Lock과 library cache Pin을
shared mode로 획득한다. 하지만, DDL문장과 같이 객체 변경작업을 수행하는 경우에는 해당 객체에 해당하는
LCO에 대해서 라이브러리 캐시 Pin을 excusive mode로 획득한다.
# Hard parsing (soft parsing 과정에서 검색 실패 즉 동일한 LCO검색이 실행한 경우 진행된다.)
1. 동일한 SQL문장이 존재하지 않는다면 shared pool latch를 획득하고 가장 적절한 크기의 Free chunk를 free list에서 찾음.
2. shared pool latch를 획득하는 과정에서 경합이 발생하면 latch:shared pool 이벤트를 대기
3. Free chunk가 확보될 때까지 계속해서 shared pool latch를 획득.
a. 최적 크기의 프리 청크가 존재하지 않으면 조금 더 큰 크기의 프리 청크를 찾아서
이를 split하여 사용하며
남은 청크는 다시 프리 리스트로 등록시킴.
b. 모드 프리 리스트를 탐색하고도 적절한 크기의 프리 청크를 찾지 못하면
LRU list를 탐색함.
LRU list의 청크들은 현재 Pin 되지 않은 recreatable 상태의 청크들임.
c. LRU list를 탐색하고도 적절한 크기의 청크를 확보하지 못하면 shared pool 내의
여유 메모리 공감을 추가적으로 할당.
d. 이것마저도 실패한다면 ORA-4031 에러가 발생.
4. 위의 과정을 통해 적절한 프리 청크를 찾으면 SQL 문장에 해당하는 라이브러리 캐시 Handle에 대해 라이브러리 캐시 Lock을 exclusive mode로 획득.
5. LCO 정보를 생성
6. LCO가 생성되면 라이브러리 캐시 Lock을 Null mode로 변환하고, 라이브러리 캐시 Pin을 exclusive mode로 획득한 후 실행 계획을 생성.
----------------------------------------------------------------------------------------------------------------------------------------------------
CR Snapshot
# CR Snapshot 확인
> 블록의 상태를 보는 가장 좋은 방법은 Fixed View 중 하나인 X$BH 뷰 확인.
> 이 중에서 CR 작업의 정체를 파악하려면 다음과 같은 컬럼들의 의미를 알아야 한다.
SQL> desc X$BH
-DBARFIL : 데이터파일 번호
-DBABLK : 블록 번호
-STATE : 블록 상태. 3 인 경우가 CR이다. 0 = Free, 1 또는 2 가 Current 상태의
블록이다(즉 CR의 반대)
-OBJ : 오브젝트 번호. dba_all_objects.data_object_id 또는 object_id와 조인된다.
-CR_SCN_BAS, CR_SCN_WRP : CR 블록인 경우 SCN 정보
-CR_UBA_FIL, CR_UBA_BLK : CR 블록인 경우 롤백에 사용된 언두 정보
SQL> !vi xbh.sql
select obj, dbarfil, dbablk, state, cr_scn_bas, cr_scn_wrp, cr_uba_fil, cr_uba_blk
from sys.x$bh where obj in (&object_id)
order by obj
/
session A-----------------------------------------------------------
SQL> CREATE TABLE cr_test(id INT PRIMARY KEY, name VARCHAR2(10));
SQL> INSERT INTO cr_test VALUES(1, 'name1');
SQL> COMMIT;
SQL> SELECT data_object_id FROM all_objects WHERE object_name = 'CR_TEST'
DATA_OBJECT_ID
--------------
53053 -- object_id
SQL> SELECT dbms_rowid.rowid_relative_fno(rowid), dbms_rowid.rowid_block_number(rowid)
2 FROM cr_test;
DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
------------------------------------ ------------------------------------
1 61050
-- 파일번호=1, 블럭번호=61050
SQL> ALTER SYSTEM FLUSH BUFFER_CACHE; -- buffer cache flush
--이 상태에서 세 개의 세션 Session A, B, C 에서 다음과 작업을 수행하면
--xbh.sql 스크립트를 이용해 1/61050 블록의 상태를 확인해보자.
Session A: SELECT * FROM cr_test;
Session C: @xbh
OBJ DBARFIL DBABLK STATE CR_SCN_BAS CR_SCN_WRP CR_UBA_FIL CR_UBA_BLK
---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
53053 1 61050 1 0 0 0 0
53053 1 61049 1 0 0 0 0
-- 1/61050 블록이 1번(Current) 상태로 존재함을 알 수 있다. 아직 Dirty 상태가 아니기 때문이다.
-- Update를 수행해서 Dirty 블록을 만든다.
Session A:
SQL> UPDATE cr_test SET name = 'name2';
Session C :
SQL> @xbh.sql
OBJ DBARFIL DBABLK STATE CR_SCN_BAS CR_SCN_WRP CR_UBA_FIL CR_UBA_BLK
---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
53053 1 61050 1 0 0 0 0
53053 1 61050 3 896180 0 0 0
53053 1 61049 1 0 0 0 0
-- 1/61050 블록에 대해 CR 블록(State=3)이 생겼음을 알 수 있다.
-- 즉 Update에 의해 Dirty 블록을 만들어지는 시점에 오라클은 하나의 CR snapshot을 만든다.
-- 이제 Session B에서 Dirty 블록에 대해 읽기를 수행한다.
Session B :
SQL> select * from cr_test;
SQL> @xbh.sql
OBJ DBARFIL DBABLK STATE CR_SCN_BAS CR_SCN_WRP CR_UBA_FIL CR_UBA_BLK
---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
53053 1 61050 3 896220 0 2 2193
53053 1 61050 3 896219 0 2 2193
53053 1 61050 1 0 0 0 0
53053 1 61050 3 896180 0 0 0
53053 1 61049 1 0 0 0 0
-- CR 블록이 하나 더 생겼음을 알 수 있다(맨위).
-- 이 CR 블록은 기존의 CR블록(SCN_BAS가 896220인)의 카피본이며
-- 실제 롤백시 수행되었음(CR_UBA_FIL = 2)을 알 수 있다.
-- Session B 에서 십여 차례 select * from cr_test 쿼리를 수행한다.
SQL> @xbh.sql
OBJ DBARFIL DBABLK STATE CR_SCN_BAS CR_SCN_WRP CR_UBA_FIL CR_UBA_BLK
---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
53053 1 61050 3 896277 0 2 2193
53053 1 61050 1 0 0 0 0
53053 1 61050 3 896276 0 2 2193
53053 1 61050 3 896275 0 2 2193
53053 1 61050 3 896274 0 2 2193
53053 1 61050 3 896273 0 2 2193
53053 1 61049 1 0 0 0 0
-- CR 블록이 최대 5개까지만 만들어지는 것을 확인할 수 있다.
-- Select 요청이 있을 때마다 가장 가까운 CR 블록을 이용해 새로운 CR 카피본을 만들고
-- 필요한 경우 롤백을 수행한다. 5개를 초과하면 가장 오래된 CR 블록은 밀려난다.
-- 이 값은 _DB_BLOCK_MAX_CR_DBA 파마리터에 의해 결정된다.
-- 위 결과는 Session B에서 계속해서 Select를 수행한 결과인데 CR_SCN_BAS가
-- 최근 값을 모두 바뀐 것을 확인할 수 있다.
***********************************************************************************
Time Session1 Session2
T0 …
T1 Update (Dirty block)
T2 Select CR 1(T2) 생성
T3 Select CR 2(T3) 생성
T4 Select CR 3(T4) 생성
T5 Select CR 4(T5) 생성
T6 Select CR 6(T6) 생성
T7 Select CR 7(T7) 생성 --> CR1 제거
T8 Select CR 8(T8) 생성 --> CR2 제거
***************************************************************************************
[정리]---------------------------------------------------------------------------------------
1. 왜 오라클은 최근 5개의 CR 블록을 계속 갱신하면서 유지하는가?
: 이에 대한 대답은 CR 작업을 좀 더 효율적으로 하기 위해서이다. 즉, 최대 5개까지 가장 최근의
CR 블록을 유지함으로써 과거 버전 읽기 작업에 드는 부하를 최소화하기 위함이다. 오라클은 Select
요청에 맞는 CR 블록을 생성하기 위해 CR 카피를 만들고, Undo로부터 롤백을 수행하는 일련의 작업을
수행하는데, 이 작업의 부하를 최소화하기 위해 버퍼 캐시에 최근의 CR 블록을 여러 개 유지하는 것이다.
2. 하나의 블록당 여러 개의 CR 블록을 유지함으로써 메모리의 낭비를 유발하지 않는가?
: 실제로 그렇다. 오라클의 특정 버전에서는 CR 블록 수가 너무 많아져서 버퍼 캐시의 효율성이 떨어지는
현상이 실제로 있었다. 하지만 최신 버전의 오라클은 CR 블록의 위치를 LRU 리스트의 꼬리쪽으로 위치
시킴으로써 메모리 부족 현상이 생길때 되도록 빨리 밀려나도록 해준다.
3.CR, CR, CR, ...
: 오라클의 CR 블록과 Consistent Read는 다른 DB에서는 잘 지원하지 못하는
MVRC(Multi Versioning Read Consistency)를 가능하게 하는 핵심 메커니즘이다.
----------------------------------------------------------------------------------------------------------------------------------------------------
isqlplus sysdba access
$ vi .bash_profile
export JAVA_HOME=$ORACLE_HOME/jdk
:wq
$ . .bash_profile
----------------------------------------
$ vi jazn.sh
#!/bin/sh
pushd .
cd $ORACLE_HOME/oc4j/j2ee/isqlplus/application-deployments/isqlplus/
$JAVA_HOME/bin/java \
-Djava.security.properties=$ORACLE_HOME/oc4j/j2ee/home
i/config/jazn.security.props \
-jar $ORACLE_HOME/oc4j/j2ee/home/jazn.jar \
-user "iSQL*Plus DBA/admin" \
-password welcome -shell
popd
:wq
---------------------------------------------------------
$ chmod 744 jazn.sh
$ ./jazn.sh
JAZN> adduser "iSQL*Plus DBA" expert expert
JAZN> grantrole webDba "iSQL*Plus DBA" expert
JAZN> listusers "iSQL*Plus DBA"
JAZN> exit
http://192.168.100.100:5560/isqlplus/dba > expert/expert
----------------------------------------------------------------------------------------------------------------------------------------------------
restricted database
# 제한모드 데이터베이스란?
restricted session 권한을 가진자만이 DB에 접근 할수 있도록 설정하는것을 말한다.
일반적으로 DB에 대한 유지보수 및 유지관리 업무를 관리자가 수행할 때 작업에 일관성을 유지하기 위한 수단으로 사용된다.
1. 제한모드로 DB startup
SQL> startup restrict
-- 해제
SQL> shutdown >>>>> startup
or
-- open상태에서 설정.
SQL> alter system enable restricted session; 헤제 > disable
2. 제한모드 실습
## 사용자 세션의 확인과 제한 모드를 위한 사용자의 강제 종료
오라클 관리자 세션***************************************************************************
SQL> startup
ORACLE instance started.
Total System Global Area 131142092 bytes
Fixed Size 451020 bytes
Variable Size 83886080 bytes
Database Buffers 46137344 bytes
Redo Buffers 667648 bytes
Database mounted.
Database opened.
SQL> alter user hr identified by hr account unlock;
일반 유저 세션*******************************************************************************
$ sqlplus hr/hr
SQL> select count(*) from tab;
COUNT(*)
-----------
8
오라클 관리자 세션***************************************************************************
SQL> alter system enable restricted session; >>>제한모드 설정.
System altered.
SQL> select logins from v$instance;
LOGINS
----------
RESTRICTED -----------> disable = ALLOWED
일반 유저 세션*******************************************************************************
===> 기존 세션에 대해서는 제한모드를 설정하지 않는다.
SQL> select count(*) from tab;
COUNT(*)
-----------
8
일반 유저 세션 2*****************************************************************************
[oracle@oracle oracle]$ sqlplus hr/hr
SQL*Plus: Release 9.2.0.1.0 - Production on Wed Sep 14 18:25:59 2005
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
ERROR:
ORA-01035: ORACLE only available to users with RESTRICTED SESSION privilege
오라클 관리자 세션***************************************************************************
SQL> select sid, serial#, username, status from v$session;
SID SERIAL# USERNAME STATUS
-------- --------- -------------- --------- ---------
1 1 ACTIVE
2 1 ACTIVE
3 1 ACTIVE
4 1 ACTIVE
5 1 ACTIVE
6 1 ACTIVE
7 1 ACTIVE
8 1 ACTIVE
9 1 ACTIVE
10 1 ACTIVE
11 3 SYS ACTIVE
12 4 HR INACTIVE
12 rows selected.
SQL> alter system kill session '12,4';
System altered.
SQL> select sid,serial#,username,status from v$session;
SID SERIAL# USERNAME STATUS
-------- --------- -------------- --------- ---------
1 1 ACTIVE
2 1 ACTIVE
3 1 ACTIVE
4 1 ACTIVE
5 1 ACTIVE
6 1 ACTIVE
7 1 ACTIVE
8 1 ACTIVE
9 1 ACTIVE
10 1 ACTIVE
11 3 SYS ACTIVE
12 4 HR KILLED
12 rows selected.
일반 유저 세션******************************************************************************
SQL> select count(*) from tab;
*
ERROR at line 1:
ORA-00028: your session has been killed
오라클 관리자 세션***************************************************************************
SQL> select * from dba_sys_privs
2 where privilege like '%RESTRICT%'; ←현재 restricted session 권한을 가진 사용자를 출력
GRANTEE PRIVILEGE ADM
SQL> select * from dba_sys_privs
---------------------- -------------------------- -----
DBA RESTRICTED SESSION YES
SYS RESTRICTED SESSION NO
MDSYS RESTRICTED SESSION YES
WKSYS RESTRICTED SESSION NO
CTXSYS RESTRICTED SESSION NO
SQL> grant restricted session to HR; ← HR에게 restricted session 권한 부여
Grant succeeded.
2 where privilege like '%RESTRICT%';
GRANTEE PRIVILEGE ADM
---------------------- -------------------------- -----
HR RESTRICTED SESSION NO
DBA RESTRICTED SESSION YES ← 차이?
SYS RESTRICTED SESSION NO
MDSYS RESTRICTED SESSION YES
WKSYS RESTRICTED SESSION NO
CTXSYS RESTRICTED SESSION NO
일반 유저 세션*******************************************************************************
SQL> conn scott/tiger
ERROR:
ORA-01035: ORACLE only available to users with RESTRICTED SESSION privilege
SQL> conn hr/hr
Connected.
← restricted session 권한을 가진 HR은 접속이 가능하지만 권한이 없는 사용자는 접속이 불가능함
*******************************************************************************************
<개인 실습>
⇒ SYS 사용자가 HR 사용자에게 RESTRICTED SESSION 권한과 상속 가능 권한 부여.
⇒ HR 사용자로 접속.
⇒ SCOTT 사용자에게 RESTRICTED SESSION 권한 부여하여 제한 모드 상태로 SCOTT 사용자
접속 가능하게 해주시오.
----------------------------------------------------------------------------------------------------------------------------------------------------
Creation Tablespace LAB
----------------------------------------------------------------------------------------------------------------------------------------------------
1. image backup
SQL> alter database backup controlfile to '/경로/파일명';
2. script backup1
SQL> alter database backup controlfile to trace;
>>> user_dump_dest 경로에 *.trc 파일로 생성되고 해당 파일을 열게 되면,
>>> startup nomount 절 이하가 controlfile을 재생성하는 script 임.
3. script backup2
SQL> alter database backup controlfile to trace as '/경로/파일명';
>>> user_dump_dest가 아닌 본인이 원하는 경로에 script 형식으로 backup.
4. 2,3번에서 발생하는 trace의 이름 식별하기.
SQL> alter system set tracefile_identifier = '식별자';
SQL> alter database backup controlfile to trace;
>>> 실행 시 해당 경로에 ora_12345_식별자.trc 형식으로 생성됨.
When?
: 물리적 구조변경이 발생할때마다...
------------------------------------------------------------------------------
critical vs noncritical
# non-critical (file lost) ===========================================
1. alter tablespace xxx offline immediate;
2. restore from backup (cp | restore)
if device fail ? restore new Location + rename
3. recover 명령. {database (mount) | datafile | tablespace (open)};
> 과거시점의 백업파일을 복원한 후 현재 시점으로 동기화하기위해서
> archivelog + redolog 를 적용하는 명령.
4. alter tablespace xxx online;
-LAB (file lost)-----------------------------------------------------
SQL> alter tablespace users offline immediate;
Tablespace altered.
SQL> !cp /home/oracle/backup/close/users01.dbf /u01/oradata/orcl
SQL> recover tablespace users;
Media recovery complete.
SQL> alter tablespace users online;
Tablespace altered.
-LAB (disk fail)------------------------------------------------------
SQL> alter tablespace users offline immediate;
Tablespace altered.
SQL> !cp /home/oracle/backup/close/users01.dbf /u01
SQL> alter tablespace users rename
2 datafile '/u01/oradata/orcl/users01.dbf' to '/u01/users01.dbf';
SQL> recover tablespace users;
Media recovery complete.
SQL> alter tablespace users online;
-----------------------------------------------------------------
# critical (file lost) - system or undo =================================
1. shutdown immediate
2. restore from backup
3. startup mount
if device fail ? 2. restore new Location + 3. rename
4. recover 명령. {database (mount) | datafile | tablespace (open)};
> 과거시점의 백업파일을 복원한 후 현재 시점으로 동기화하기위해서
> archivelog + redolog 를 적용하는 명령.
5. alter database open;
--------------------------------------------------------------------------
export / import > expdp / impdp
> p.3-6 Data Pump: Benefits
- DB Link를 이용한 Network Mode (NETWORK_LINK 옵션)
- Directory Object가 반드시 필요(DIRECTORY 옵션)
- expdp 옵션에 의한 객체 단위 포함/제외 가능(EXCLUDE/INCLUDE 옵션 및 향상된 QUERY 옵션)
- 제한적이긴 하지만 Parallel 가능(PARALLEL 옵션)
- Master Table에 의한 중지 작업 재시작 및 작업 변경(추가 및 삭제)이 가능
- REMAP_SCHEMA, REMAP_DATAFILE, REMAP_TABLESPACE 등 새로운 옵션
> p.3-8
- client가 oracle db에 logon 하면 shadow process 가 생성된다.
shadow process는 client의 Data Pump API 요청을 처리한다(A).
일단 job이 실행되면 shadow process(B)의 주업무는 client로부터 GET_STATUS 요청에 대해 서비스하는 것이다.
Client(A)가 detach되면 해당 shadow process는 없어진다.
A. DBMS_DATAPUMP.OPEN 요청
- job을 생성
- master table 생성
- AQ queue 생성 : process간 통신
- master control process(MCP) 생성
B. MCP는 Data pump job의 실행과 순서를 control한다
- job status, job description, restart, master table에 있는 정보를 dump한는 것을 maintain
- MCP는 DMnn 이다.
C. START_JOB 요정에 따라 MCP(master control process)는 PARALLEL parameter에 의거 몇개의 work process를
만든다. work process(DWnn)는 MPC의 요청을 수행한다. 주로 Data와 Metadata의 load/unload를 담당.
- Loading/unloading을 위한 data access method로 external table path가 선택되면 work process는
load/unload assignment에 따라서 여러개의 parallel execution servers의 작업을 coordinate한다.
Dump File Sets <--|
Client A Shaow Process --> Q AQ ^ |
U (DMnn) Q | |
Client B Shaow Process --> E <-- MCP --> Master Table U <--->Work process1 --| |
| U ^ | E <--->Work Process2 --| |
| E | ------------------>U <--->Work Process3 -- |
----------------------->JOB E <--->Work Process4 ---- PX Server1--|
(Ext Table Path) |_PX Server2--|
1. Client Process -> DBMS_DATAPUMP.OPEN
1) Create JOB : Master Table, AQ Queue, Master Control Process
2) Service : Get_Status
2. Master Control Process(MCP)
- Pump Job의 실행과 순서 관리
- DMnn
3. START_JOB 요청으로
- PARALLEL Patameter에 의거 Work Process를 실행(DWnn:01~04)
> p.3-9
* Direct Path 제약조건
- Data pump 는 Direct path loading(using direct path API) 또는 External Tables을 사용하여
table row data에 access한다.
- Data Pump 가 자동으로 둘 중에 적절한 방법을 선택한다.
Table structure가 허용하거나 Maximum single-stream performance가 요구될때 direct path가
사용된다. 그러나 아래의 경우 또는 table이 encrypted column을 포함하거나 load시간과 unload시간
에 partition이 다를 경우 data pump는 external table을 사용한다.
* direct path가 안되고 external table이 되는 경우
- fine-grained access control을 가진 table이 insert/select mode에서 enable된 경우
- LOB 컬럼에 대해 domain index가 존재할때
- Clustered table 이 존재할 경우
- Table에 active trigger가 define 된 경우
- Partition table에 global index가 있을 때 single-partition load를 할 경우
- BFILE 또는 opaque type 컬럼
- FK
- VARRAY columns with an embedded opaque type
> p.3-10 Data Pump File Locations
- Data pump file 종류
- DUMP file : data와 metadata를 포함.
- LOG file : operation과 관련된 message를 기록.
- SQL file : impdp에서 SQLFILE operation의 결과를 기록
- Data Pump는 server-based 이므로 Oracle directory path를 통해서 Data Pump file에 access한다.
Absolute path는 보안상 지원되지 않는다.
- Order of precedence of file Locations
1) per-file directory
- dump file, log file, sql file 마다 지정될수 있다. 콜론(:)으로 deirecoty 와 file name 을 구분한다.
EX) dumpfile=AA:A.dmp
2) DIRECTORY parameter
- directory object를 사용.
EX)
Create Directory DIR_PJH as '/home/oracle10g/test/';
Ggrant read, write On Directory DIR_PJH to SCOTT;
Directory=AA
Dumpfile=A.dmp
3) DATA_PUMP_DIR 환경변수
- DIRECTORY Parameter를 대신하여 directory object name을 설정.
EX)
export DATA_PUMP_DIR=AA
Dumpfile=A.dmp
- 위의 모든 경우에 시도하려는 operation에 대해 directory object에 대해 적절한 access privs가 있어야 한다.
Export할 경우 모든 file에 대해 write access가 필요.
Import할 경우 dump file에 대해 read access, log file과 sql file에 대해 write access가 필요.
> p.3-12 Data Pump File Naming and Size
1) DUMPFILE
- file list는 , 로 분리
- %U template --> 결과 파일명에서 고정너비2자로 확장되면 01에서 시작하여 정수 단위로 일정하게 증가.
- DUMPFILE 이 지정되어 있지 않으면 expdat.dmp 가 default로 사용된다. default로 autoextensible.
2) FILESIZE
- FILESIZE 가 지정되어 있으면 각 file은 FILESIZE안으로 만들어지고 늘어날수 없다. dump 공간이 더 필요하고
template %U가 지정되었다면, 새로운 파일이 생성된다. 그렇치 않으면 사용자는 new file을 add하라는
메세지를 받는다.
3) PARALLEL
- %U가 지정되면 PARALLEL patameter의 갯수만큼 초기에 file이 생성된다.
4) 기존에 존재하는 file과 이름이 중복될 경우 overwrite하지 않고 에러를 발생시키고 job이 abort된다.
5) 복수개의 dump file template가 제공되면 round-robin fashion으로 dump file을 생성하는 데 사용.
> p.3-14 Data Pump and Filtering
(1) Find-grained object selection
- 기존의 exp/imp는 index, trigger, grant, constriant를 포함하거나 제외할 수 만 있으나
data pump는 virtually any type of object를 포함하거나 제외할 수 있다.
- EXCLUDE 와 INCLUDE는 상호배타적이다.
- INCLUDE = object_type[:"name_expr"]
- EXCLUDE = object_type[:"name_expt"]
EX) 모든 view, 모든 package, EMP로 시작하는 Index만 제외
EXCLUDE=view
EXCLUDE=package
EXCLUDE=INDEX:"LIKE 'EMP%' "
(2) Data Selection
- CONTENT = ALL(def) | METADATA_ONLY | DATA_ONLY
- QUERY = [Schema.][table_name:]"query_clause"
- CONTENT에 data_only가 사용되면 EXCLUDE 와 INCLUDE를 사용할 수 없다.
- QUERY=hr.employees:"WHERE department_id in (10,20) and salary < 1600 ORDER BY department_id"
<--특정 table을 지정해서 해당 table로 한정. imp시에도 적용.
> p.3-15 Data Pump Import Transformations(변경)
- Dump file의 metadata는 XML로 저장되어있기 때문에 import시 DDL이 적용될 때 쉽게 변경할 수 있다.
1) Remap
A. REMAP_DATAFILE
- REMAP_DATAFILE='c:\oradata\tbs6.f':'/u1/tbs6.f'
- 서로 다른 file-system 형식을 가지는 platform으로 옮기는 경우. (DB migration시 유용)
B. REMAP_TABLESPACE :export 받은 데이터 속한 tablespace 에서 다른 tablespace로 Remapping하고자 하는 경우
C. REMAP_SCHEMA : 유저 스키마로 export 받은 데이터를 B 유저 스키마로 import 하고자 할때
- 기존의 fromuser, touser를 제공.
> p.3-16 TRANSFORM
- TRANSFORM= SEGMENT_ATTRIBUTES | STORAGE:{y|n}[:TABLE | INDEX]
- TRANSFORM 으로 storage와 tablespace 또는 storage에 대한 DDL이 생성되지 않게 할 수 있다.
Target DB의 storage가 Source DB의 storage와 많이 다를 경우 유용하다.
> p.3-20 Parallel Full Export and Import
- 4개의 work process를 가진 full export,
Pump file은 DATADIR1, DATADIR2, DATADIR3, DATADIR4 네곳에 라운드로빈 방식으로 생성된다.
2G를 넘지 않으면서... 최소4개 생성.
Job 과 master table 이름은 default로 SYSTEM_EXPORT_FULL_01 를 가진다.
- expdp로 받은 dump file을 network를 통해 NET_STORAGE_1 이라는 directory object위치로
보내졌다. Default import는 dump set 전체를 import하는 것이므로 Full=y 는 필요없다.
Job 과 master table 이름은 default로 SYSTEM_IMPORT_FULL_01 를 가진다.
> p.3-21 Limited Schema Export (fine-grained)
- HR, OE schema에서 모든 func, prod, pkg, user-defined type, PRODUCT로 시작하는 view를 export한다.
Schema definition과 system priv graints는 export되지 않는다.
- 실제 import는 하지 않고 dmp file에서 DDL 문장만 뽑아낸다.
> p.3.22 Network Mode Import (DB Link)
- Source DB에 dblink로 붙어서 hr, sh, payroll schema를 가져온다음 imp 한다.
이때 payroll schema로 finacne schema로 만들어 진다.
SYSTEM은 IMPORT_FULL_DATABASE rol을 가지고 있고 Source DB에 대해서는 EXPORT_FULL_DATABASE role
을 가지므로...Target DB에 해당 schema definition이 없으면 만들어진다.
flashback_time은 예전의 CONSISTENT와 동일.
> p.3-23 Attaching to Existing Job
- 중지.
Attach session은 terminate 되고 실행되던 job은 controlled fashion으로 run down 된다.
해당 Job은 dump file과 SYSREM.EXP_TS1 table이 disturbed 되지 않는한 startable 하다.
> p.3-24 Restarting Stopped Job
> expdp system/manager attach=exp_ts1 <--같은 schema안에 여러개의 outstanding job이 있으면 job name지정
...
Export> parallel=4
Export> start_job
Export> status =600 <--10분. detailed per-work process가 10분 단위로 regualr status message를 보여준다.
...
KILL_JOB로 job을 kill
<--status, status=600(초)
stop_job,
start_job,
continue_client:attach한 session이 계속 받아서 expdp 실행.(logging mode로 전환)
exit_client: Attach를 빠져 나옴. expdp는 background로 실행.
parallel=4,
> p.3-27 External Table Population
- Create Table As select ... 로 External Flat File을 만들수 있다.(10g)
- External Flat File로 External Table을 통하여 Insert ....Select로 타 Table로 insert 한다. (기존)
- External Table은 복잡한 ETL 에 적합.
- external flat file에 대한 insert/update/delete 는 불가능하다. ORA-30675 error
- external flat file은 이동될수 있고 같은 DB나 다른 DB의 다른 External Table에 대해 사용될수 있으나
오직 ORACLE_DATAPUMP access driver에 의해서만 사용될 수 있다.
- ORACLE_DATAPUMP driver 를 사용.
~~~~~~~~~~~~~~~ External Table API <> Direct Path API
> p.3-29 External Table Parallel Population Operation
- External Table은 일반적으로 크기 때문에 Parallel operation으로 unload한다(복수개의 file이 생성).
Parallel operation은 External Table이 parallel로 define된 경우 가능.
- Exactly one parallel execution server per file.
- 각각의 I/O server process는 자신의 file을 요구하므로 Location 절에 있는 file의 갯수가 지정된
parallel degree 와 같아야 한다. 지정된 parallelism degree 보다 작은 files인 경우 Location에 있는 file
갯수와 맞추기 위해 degree of parallelism은 낮아진다. 반대로 files의 갯수가 많은 경우 여분의 file은
무시된다.
Coordinator
|
|-------------------------------------------|
Parallel Execution Parallel Execution Parallel Execution
Server 1 Server 2 Server 3
| | |
V V V
generated file 1 generated file 2 generated file 3
- 기존 9i 의 external table
CREATE TABLE empxt (empno NUMBER(4),
ename VARCHAR2(10),
job VARCHAR2(9),
mgr NUMBER(4),
hiredate DATE,
sal NUMBER(7,2),
comm NUMBER(7,2),
deptno NUMBER(2)
)
ORGANIZATION EXTERNAL ( TYPE ORACLE_LOADER <---기존
DEFAULT DIRECTORY emp_dir_sqlt#
ACCESS PARAMETERS ( records delimited by newline
badfile emp_dir:'empxt.bad'
logfile emp_dir:'empxt.log'
fields terminated by ','
missing field values are null
( empno, ename, job, mgr,
hiredate char date_format date mask "dd-mon-yy",
sal, comm, deptno
)
)
Location ('emp.dat')
);
- 10g 에서 External Flat File을 만드는 예제 <--그럼 external table은 언제/어떻게 만들어 지나?
Create Table emp_ext(first_name,
last_name,
department_name
)
Organization External ( Type ORACLE_DATAPUMP <---변경
Default Directory ext_dir
Location ('emp1.exp','emp2.exp','emp3.exp') <---|
) |
Parallel 3 <--병렬 ----------------file하나당 하나의 parallel process가 --|
+
As
Select e.first_name, e.last_name, d.department_name
From employee e, department d
Where e.department_id = d.department_id
and d.department_name in ('Marketing','Purchasing');
> p.3-31 External Table Projected Columns
- External Flat file의 data format error로 row가 reject 될 수 있는데 projected column feature
은 External Table에 access하는 SQL의 column에 상관없이 일관된 consistent result를 보장.
- 예전(9i)에서는 참조하는 컬럼만 access driver에 의해 projected out 되었다. 즉 REFERENCED(참조).
10g 부터는 ALL(Default)을 추가하였다.
Alter table order_item_ext PROJECT COLUMN {(ALL) | REFERENCED};
----------<--select하는 컬럼만 검사하여..9i
- Default는 ALL 임.
- REFERENCED 는 data가 safe하다고 예상될 때 성능향상을 위해서 유용.
order_id line_id
-------- -------
2311, 1,...
2312, A,...
Alter table order_item_ext PROJECT COLUMN REFERENCED;
select count(order_id ) from order_item_ext; --> 2
select count(line_id ) from order_item_ext; --> 1
select count(order_id ) from order_item_ext; --> 1
select count(line_id ) from order_item_ext; --> 1
----------------------------------------------------------------------------------------------------------
SQL> alter user scott identified by tiger account unlock;
SQL> conn scott/tiger
SQL> select * from tab;
TNAME TABTYPE CLUSTERID
------------------------------ ------- ----------
BONUS TABLE
DEPT TABLE
EMP TABLE
SALGRADE TABLE
[~/backup/dump]$ exp scott/tiger file=/home/oracle/backup/dump/exp_test.dmp tables=(emp, dept)
=====장애발생===================================
SQL> conn scott/tiger
SQL> drop table dept cascade constraints;
SQL> drop table emp;
SQL> purge recyclebin;
SQL> select * from tab;
TNAME TABTYPE CLUSTERID
------------------------------ ------- ----------
BONUS TABLE
SALGRADE TABLE
===============================================
[~/backup/dump]$ imp scott/tiger file=/home/oracle/backup/dump/exp_test.dmp tables=(emp, dept)
SQL> select * from tab;
TNAME TABTYPE CLUSTERID
------------------------------ ------- ----------
BONUS TABLE
DEPT TABLE
EMP TABLE
SALGRADE TABLE
-------------------------------------------------------------------------------------------------------------
Directory created.
SYS> grant read, write on directory dump1 to public;
Grant succeeded.
1)
HR> CREATE TABLE extdp_test_tb1
2 ORGANIZATION EXTERNAL
3 (TYPE ORACLE_DATAPUMP
4 DEFAULT DIRECTORY dump1
5 Location('ext_emp01.dmp','ext_emp02.dmp','ext_emp03.dmp')
6 )
7 PARALLEL 3
8 AS
9* SELECT * FROM HR.employees
HR> /
Table created.
HR> desc extdp_test_tb1
Name Null? Type
----------------------------------------- -------- --------------
EMPLOYEE_ID NUMBER(6)
FIRST_NAME VARCHAR2(20)
LAST_NAME NOT NULL VARCHAR2(25)
EMAIL NOT NULL VARCHAR2(25)
PHONE_NUMBER VARCHAR2(20)
HIRE_DATE NOT NULL DATE
JOB_ID NOT NULL VARCHAR2(10)
SALARY NUMBER(8,2)
COMMISSION_PCT NUMBER(2,2)
MANAGER_ID NUMBER(6)
DEPARTMENT_ID NUMBER(4)
HR> select * from extdp_test_tb1;
EMPLOYEE_ID FIRST_NAME LAST_NAME
----------- -------------------- -------------------------
EMAIL PHONE_NUMBER HIRE_DATE JOB_ID
------------------------- -------------------- ------------------- ----------
SALARY COMMISSION_PCT MANAGER_ID DEPARTMENT_ID
---------- -------------- ---------- -------------
100 Steven King
SKING 515.123.4567 1987-06-17 00:00:00 AD_PRES
24000 90
101 Neena Kochhar
NKOCHHAR 515.123.4568 1989-09-21 00:00:00 AD_VP
17000 100 90
...
total 73M
drwxr-xr-x 2 oracle oinstall 4.0K Mar 30 12:53 .
drwxr-xr-x 17 oracle dba 4.0K Mar 30 12:53 ..
...
-rw-r--r-- 1 oracle oinstall 82 Mar 30 12:53 EXTDP_TEST_TB1_16611.log
-rw-r----- 1 oracle oinstall 82 Mar 30 12:53 EXTDP_TEST_TB1_16627.log
-rw-r----- 1 oracle oinstall 82 Mar 30 12:53 EXTDP_TEST_TB1_16629.log
-rw-r----- 1 oracle oinstall 82 Mar 30 12:53 EXTDP_TEST_TB1_16631.log
-rw-r----- 1 oracle oinstall 16K Mar 30 12:53 ext_emp01.dmp
-rw-r----- 1 oracle oinstall 16K Mar 30 12:53 ext_emp02.dmp
-rw-r----- 1 oracle oinstall 20K Mar 30 12:53 ext_emp03.dmp
...
2)
HR> CREATE TABLE extdp_test_tb2
2 ORGANIZATION EXTERNAL
3 (TYPE ORACLE_DATAPUMP
4 DEFAULT DIRECTORY dump1
5 Location('emp_dept_join01.dmp')
6 )
7 PARALLEL 3
8 AS
9 SELECT d.department_name, e.last_name, e.salary, e.department_id
10 FROM hr.employees e, hr.departments d
11 where e.department_id = d.department_id
12* and e.department_id < 70
Table created.
HR> desc extdp_test_tb2
Name Null? Type
----------------------------------------- -------- ----------------------------
DEPARTMENT_NAME NOT NULL VARCHAR2(30)
LAST_NAME NOT NULL VARCHAR2(25)
SALARY NUMBER(8,2)
DEPARTMENT_ID NUMBER(4)
HR> select * from extdp_test_tb2;
DEPARTMENT_NAME LAST_NAME SALARY
------------------------------ ------------------------- ----------
DEPARTMENT_ID
-------------
Shipping OConnell 3000
50
Shipping Grant 2600
50
...
3)
생성된 파일을 target db 로 복사
$ mkdir /home/oracle/dp2
$ sqlplus system/oracle
SYSTEM> CREATE OR REPLACE DIRECTORY dump2 AS '/home/oracle/dp2';
SYSTEM> GRANT read, write on directory dump2 TO hr ;
SYSTEM> !cp /home/oracle/dp/EMP_DEPT_JOIN01.DMP /home/oracle/dp2/
SYSTEM> conn hr/hr
SYSTEM> CREATE TABLE extdp_test_tb3
2 (DEPARTMENT_NAME VARCHAR2(30)
3 ,LAST_NAME VARCHAR2(25)
4 ,SALARY NUMBER(8,2)
5 ,DEPARTMENT_ID NUMBER(4)
6 )
7 ORGANIZATION EXTERNAL
8 (TYPE ORACLE_DATAPUMP
9 DEFAULT DIRECTORY dump2
10 Location ('EMP_DEPT_JOIN01.DMP') ) ;
select * from extdp_test_tb3 ;
[ocp@orcl : /home/oracle]$ sqlplus sys/oracle as sysdba
SYS> create directory dump1 as '/home/oracle/dp';
Directory created.
SYS> grant read, write on directory dump1 to public;
Grant succeeded.
SYS> exit
[ocp@orcl : /home/oracle]$ mkdir dp
[ocp@orcl : /home/oracle]$ expdp system/oracle dumpfile=full.dmp directory=dump1 full=y job_name=Lucie
Export: Release 10.2.0.1.0 - Production on Monday, 30 March, 2009 9:57:09
Copyright (c) 2003, 2005, Oracle. All rights reserved.
Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
Starting "SYSTEM"."LUCIE": system/******** dumpfile=full.dmp directory=dump1 full=y job_name=Lucie
Estimate in progress using BLOCKS method...
Processing object type DATABASE_EXPORT/SCHEMA/TABLE/TABLE_DATA
ORA-39139: Data Pump does not support XMLSchema objects. TABLE_DATA:"OE"."PURCHASEORDER" will be skipped.
Total estimation using BLOCKS method: 61 MB
Processing object type DATABASE_EXPORT/TABLESPACE
Processing object type DATABASE_EXPORT/PROFILE
Processing object type DATABASE_EXPORT/SYS_USER/USER
Processing object type DATABASE_EXPORT/SCHEMA/USER
Processing object type DATABASE_EXPORT/ROLE
Processing object type DATABASE_EXPORT/GRANT/SYSTEM_GRANT/PROC_SYSTEM_GRANT
Processing object type DATABASE_EXPORT/SCHEMA/GRANT/SYSTEM_GRANT
Processing object type DATABASE_EXPORT/SCHEMA/ROLE_GRANT
Processing object type DATABASE_EXPORT/SCHEMA/DEFAULT_ROLE
Processing object type DATABASE_EXPORT/SCHEMA/TABLESPACE_QUOTA
Processing object type DATABASE_EXPORT/RESOURCE_COST
Processing object type DATABASE_EXPORT/TRUSTED_DB_LINK
Processing object type DATABASE_EXPORT/SCHEMA/SEQUENCE/SEQUENCE
Processing object type DATABASE_EXPORT/SCHEMA/SEQUENCE/GRANT/OWNER_GRANT/OBJECT_GRANT
Processing object type DATABASE_EXPORT/DIRECTORY/DIRECTORY
Processing object type DATABASE_EXPORT/DIRECTORY/GRANT/OWNER_GRANT/OBJECT_GRANT
Processing object type DATABASE_EXPORT/CONTEXT
Processing object type DATABASE_EXPORT/SCHEMA/PUBLIC_SYNONYM/SYNONYM
Processing object type DATABASE_EXPORT/SCHEMA/SYNONYM
Processing object type DATABASE_EXPORT/SCHEMA/TYPE/INC_TYPE
-- Ctrl + C 로 강제 중지 시킨다!!!
Export> status
Job: LUCIE
Operation: EXPORT
Mode: FULL
State: EXECUTING
Bytes Processed: 0
Current Parallelism: 1
Job Error Count: 0
Dump File: /home/oracle/dp/full.dmp
bytes written: 4,096
Worker 1 Status:
State: EXECUTING
Object Type: DATABASE_EXPORT/SYSTEM_PROCOBJACT/POST_SYSTEM_ACTIONS/PROCACT_SYSTEM
Completed Objects: 3
Total Objects: 3
Worker Parallelism: 1
Export> stop_job
Are you sure you wish to stop this job ([yes]/no): yes
[ocp@orcl : /home/oracle]$ ss
SQL*Plus: Release 10.2.0.1.0 - Production on Mon Mar 30 09:59:23 2009
Copyright (c) 1982, 2005, Oracle. All rights reserved.
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
SYS> select owner_name,job_name,operation,job_mode,state from dba_datapump_jobs;
OWNER_NAME JOB_NAME OPERATION JOB_MODE STATE
------------------------------------------------------------------------
SYSTEM LUCIE EXPORT FULL NOT RUNNING
Disconnected from Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
[ocp@orcl : /home/oracle]$ expdp system/oracle attach=lucie
Export: Release 10.2.0.1.0 - Production on Monday, 30 March, 2009 9:59:40
Copyright (c) 2003, 2005, Oracle. All rights reserved.
Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
Job: LUCIE
Owner: SYSTEM
Operation: EXPORT
Creator Privs: FALSE
GUID: 664B8FEE4B8286B7E040007F01001E87
Start Time: Monday, 30 March, 2009 9:59:45
Mode: FULL
Instance: orcl
Max Parallelism: 1
EXPORT Job Parameters:
Parameter Name Parameter Value:
CLIENT_COMMAND system/******** dumpfile=full.dmp directory=dump1 full=y job_name=Lucie
State: IDLING
Bytes Processed: 0
Current Parallelism: 1
Job Error Count: 0
Dump File: /home/oracle/dp/full.dmp
bytes written: 573,440
Worker 1 Status:
State: UNDEFINED
Export> start_job
----다른 SYS 세션 --------------------------------------------------------
SYS> select owner_name,job_name,operation,job_mode,state from dba_datapump_jobs;
OWNER_NAME JOB_NAME OPERATION JOB_MODE STATE
------------------------------------------------------------------------
SYSTEM LUCIE EXPORT FULL IDLING
----다른 SYS 세션 --------------------------------------------------------
Export> status
Job: LUCIE
Operation: EXPORT
Mode: FULL
State: EXECUTING
Bytes Processed: 0
Current Parallelism: 1
Job Error Count: 0
Dump File: /home/oracle/dp/full.dmp
bytes written: 577,536
Worker 1 Status:
State: EXECUTING
Export> status
Job: LUCIE
Operation: EXPORT
Mode: FULL
State: EXECUTING
Bytes Processed: 18,075,304
Percent Done: 30
Current Parallelism: 1
Job Error Count: 0
Dump File: /home/oracle/dp/full.dmp
bytes written: 36,999,168
Worker 1 Status:
State: EXECUTING
Object Schema: SH
Object Name: SALES
Object Type: DATABASE_EXPORT/SCHEMA/TABLE/TABLE_DATA
Completed Objects: 12
Total Objects: 676
Worker Parallelism: 1
Export> status
Job: LUCIE
Operation: EXPORT
Mode: FULL
State: COMPLETING
Bytes Processed: 54,644,921
Percent Done: 100
Current Parallelism: 1
Job Error Count: 0
Dump File: /home/oracle/dp/full.dmp
bytes written: 75,874,304
Worker 1 Status:
State: WORK WAITING
[ocp@orcl : /home/oracle]$ cd dp/
[ocp@orcl : /home/oracle/dp]$ ls
export.log full.dmp
[ocp@orcl : /home/oracle/dp]$ vi export.log
[ocp@orcl : /home/oracle/dp]$ ls -alh
total 73M
drwxr-xr-x 2 oracle oinstall 4.0K Mar 30 10:01 .
drwxr-xr-x 16 oracle dba 4.0K Mar 30 10:01 ..
-rw-r--r-- 1 oracle oinstall 58K Mar 30 10:01 export.log
-rw-r----- 1 oracle oinstall 73M Mar 30 10:01 full.dmp
[ocp@orcl : /home/oracle/dp]$
특정 스키마 DDL 스크립트 생성 실습
######################################
[ocp@orcl : /home/oracle]$ impdp system/oracle directory=dump1 dumpfile=full.dmp schemas=scott sqlfile=ddl_scott.sql
Import: Release 10.2.0.1.0 - Production on Monday, 30 March, 2009 12:36:25
Copyright (c) 2003, 2005, Oracle. All rights reserved.
Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
Master table "SYSTEM"."SYS_SQL_FILE_SCHEMA_01" successfully loaded/unloaded
Starting "SYSTEM"."SYS_SQL_FILE_SCHEMA_01": system/******** directory=dump1 dumpfile=full.dmp schemas=scott sqlfile=ddl_scott.sql
Processing object type DATABASE_EXPORT/SCHEMA/USER
Processing object type DATABASE_EXPORT/SCHEMA/GRANT/SYSTEM_GRANT
Processing object type DATABASE_EXPORT/SCHEMA/ROLE_GRANT
Processing object type DATABASE_EXPORT/SCHEMA/DEFAULT_ROLE
Processing object type DATABASE_EXPORT/SCHEMA/PROCACT_SCHEMA
Processing object type DATABASE_EXPORT/SCHEMA/TABLE/TABLE
Processing object type DATABASE_EXPORT/SCHEMA/TABLE/INDEX/INDEX
Processing object type DATABASE_EXPORT/SCHEMA/TABLE/CONSTRAINT/CONSTRAINT
Processing object type DATABASE_EXPORT/SCHEMA/TABLE/CONSTRAINT/REF_CONSTRAINT
Job "SYSTEM"."SYS_SQL_FILE_SCHEMA_01" successfully completed at 12:36:37
[ocp@orcl : /home/oracle]$ cd dp/
[ocp@orcl : /home/oracle/dp]$ ls
ddl_scott.sql export.log full.dmp import.log
[ocp@orcl : /home/oracle/dp]$ vi ddl_scott.sql
table import
##########################################
1) content=data_only 포함하지 않은 경우 (해당 object가 존재하지 않는 경우)
[ocp@orcl : /home/oracle/dp]$ impdp system/oracle dumpfile=full.dmp directory=dump1 job_name=data_import logfile=table_log tables=scott.dept
2) 특정 사용자 (schema) import
SQL> drop user scott cascade;
[ocp@orcl : /home/oracle/dp]$ impdp system/oracle dumpfile=full.dmp directory=dump1 job_name=data_import logfile=table_log schemas=scott
------------------------------------------------------------------------------------------------------------------------
flat file이란 그냥 raw data만 있다고 생각하면 되겠다. CSV(Comma Separated Values)파일도 이에 해당한다.
External Table은 9i부터 지원되므로 9i이전에서는 organization external에서 에러가 발생한다.
-virtual read-only table
-인덱스 사용 못함(파일처리가 빠르기때문에 필요없음)
-OS명령을 통해 insert, update, delete수행
-external table간의 조인 가능, external-regular table간의 조인 가능
7369,SMITH,CLERK,20
7499,ALLEN,SALESMAN,30
7521,WARD,SALESMAN,30
7566,JONES,MANAGER,20
7654,MARTIN,SALESMAN,30
7698,BLAKE,MANAGER,30
7782,CLARK,MANAGER,10
7788,SCOTT,ANALYST,20
7839,KING,PRESIDENT,10
7844,TURNER,SALESMAN,30
7876,ADAMS,CLERK,20
7900,JAMES,CLERK,30
7902,FORD,ANALYST,20
7934,MILLER,CLERK,10
연결되었습니다.
2 '/home/oracle/labs' ;
디렉토리가 생성되었습니다.
2 (
3 empno char(4),
4 ename char(10),
5 job char(9),
6 deptno char(2)
7 )
8 organization external
9 (
10 type oracle_loader
11 default directory test_dir
12 access parameters
13 (
14 fields terminated by ','
15 (empno,ename,job,deptno)
16 )
17 Location ('emp.dat')
18 )
19 reject limit 100
20 ;
이름 널? 유형
----------------------------------------- -------- ----------------------------
EMPNO CHAR(4)
ENAME CHAR(10)
JOB CHAR(9)
DEPTNO CHAR(2)
---- ---------- --------- --
7369 SMITH CLERK 20
7499 ALLEN SALESMAN 30
7521 WARD SALESMAN 30
7566 JONES MANAGER 20
7654 MARTIN SALESMAN 30
7698 BLAKE MANAGER 30
7782 CLARK MANAGER 10
7788 SCOTT ANALYST 20
7839 KING PRESIDENT 10
7844 TURNER SALESMAN 30
7876 ADAMS CLERK 20
7900 JAMES CLERK 30
7902 FORD ANALYST 20
7934 MILLER CLERK 10
----------
14
2 where empno=7521;
---- ---------- --------- --
7521 WARD SALESMAN 30
[조인시의 분석]
SQL> create table emp2_external
2 (
3 empno char(4),
4 ename char(10),
5 job char(9),
6 deptno char(2)
7 )
8 organization external
9 (
10 type oracle_loader
11 default directory test_dir
12 access parameters
13 (
14 fields terminated by ','
15 (empno, ename, job, deptno)
16 )
17 Location ('emp2.dat')
18 );
테이블이 생성되었습니다.
2 from emp_external a, emp_external b
3 where a.empno = b.empno
4 and a.empno = 7900
5 and b.empno = 7900;
---- --------- ---------
7900 CLERK CLERK
[external table - regular table간의 조인]
2 (
3 empno char(4),
4 ename char(10),
5 job char(9),
6 deptno char(2)
7 );
2 from emp_external a, emp_regular b
3 where a.empno = b.empno
4 and a.empno = 7900
5 and b.empno = 7900;
---- --------- ---------
7900 DBA CLERK
/u01/oradata의 하위에 datapump라는 폴더를 하나 생성한다. 생성된 폴더로 이동한 후에
system 계정으로 접속한다.
잠겨있는 sh유저에 대해서 계정을 풀어주고 생성한 datapump에 대해서 다음과
같은 권한을 준다.
create directory dirpump as '/u01/oradata/datapump';
grant read, write on directory dirpump to sh;
sh 유저로 접속한다.
select count(*) from sales;
백업대상인 sales의 테이블 용량을 알아본다.
select sum(bytes)/1024/1024 from user_segments
where segment_name='SALES';
SUM(BYTES)/1024/1024
-----------------------
15.875
expdp_check.par라는 파일을 vi편집기로 생성한후에 다음과 같이 입력한다.
directory=dirpump : 논리적 경로를 담고 있는 디렉토리
job_name=datapump : 작업 프로세스명
estimate=statistics : 예상 작업 통계 생성
estimate_only=Y : 오로지 예상측정량만 계산
logfile=expdp_pump.log : 출력에 대한 로그 기록
filesize=20M : 실제 데이터를 10M씩 분할 생성
tables=sales : 테이블은 sales를 선택
4번째와 5번째 옵션을 보면 측정만 할뿐 실제로 백업을 수행하지
않으므로 수행하기 위해서는 estimate 두 라인을 삭제해준다.
마지막라인에는 sales 라는 테이블을 백업하는 라인이고 스키마인 sh
를 백업할려면 다음과 같이 수정해준다.
schemas=sh
sh대신에 sys, hr, oe등등 모두 가능하다
$ expdp parfile=expdp_check.par
[-----$ expdp help=y-----옵션 확인]
Starting "SH"."DATAPUMP": parfile=expdp_check.par
Estimate in progress using STATISTICS method...
Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
Processing object type -----------------내용 확인
estimated "SH"."sales" 85.04 MB
Total estimation using STATISTICS method: 85.04 MB
Job "SH"."DATAPUMP" successfully completed at 11:41:00(완료)
$ cp expdp_check.par expdp_pump.par
$ vi expdp_pump.par
userid=sh/sh
directory=dirpump
job_name=datapump
logfile=expdp_pump.log
dumpfile=expdp_pump%U.dmp : 출력할 덤프파일명(파일 분할)
filesize=20M
tables=sales
$ expdp parfile=expdp_pump.par
Export: Release 10.2.0.1.0 - Production on Sunday, 11 November, 2007 11:42:40
Copyright (c) 2003, 2005, Oracle. All rights reserved.
Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
Estimate in progress using BLOCKS method...
Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
Total estimation using BLOCKS method: 151 MB
Processing object type TABLE_EXPORT/TABLE/TABLE
Processing object type TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
. . exported "SH"."sales" 124.1 MB 8192000 rows
Master table "SH"."DATAPUMP" successfully loaded/unloaded
******************************************************************************
Dump file set for SH.DATAPUMP is:
/app/oracle/oradata/datapump/expdp_pump01.dmp
/app/oracle/oradata/datapump/expdp_pump02.dmp
/app/oracle/oradata/datapump/expdp_pump03.dmp
/app/oracle/oradata/datapump/expdp_pump04.dmp
/app/oracle/oradata/datapump/expdp_pump05.dmp
/app/oracle/oradata/datapump/expdp_pump06.dmp
/app/oracle/oradata/datapump/expdp_pump07.dmp
Job "SH"."DATAPUMP" successfully completed at 11:43:14
$ ls (---파일이 분할된것을 확인할수 있다.---)
$ ll
-----파일 분할 된것 확인-----
userid=sh/sh
directory=dirpump
job_name=datapump
logfile=impdp_pump.log
dumpfile=expdp_pump%U.dmp(파일이 분할되어있는경우만)
tables=sales
or
schemas=sh
table_exists_action=append
$ ls
expdp_check.par expdp_pump01.dmp expdp_pump04.dmp expdp_pump07.dmp
expdp_pump.log expdp_pump02.dmp expdp_pump05.dmp impdp_pump.par
expdp_pump.par expdp_pump03.dmp expdp_pump06.dmp
$ impdp parfile=impdp_pump.par
DB를 처음 생성할 때 자동으로 DEFAULT 프로파일이 생성되며,
프로파일을 지정하지 않고 생성된 유저는 이 프로파일 정책을 따르게 된다.
DEFAULT 프로파일은 최초에는 어떠한 제한도 가지고 있지 않는다.
1. 프로파일 생성
SQL> CREATE PROFILE any_profile_name LIMIT
CPU_PER_SESSION UNLIMITED -- 해당 세션에 허용된 CPU 시간(1/100초)
CPU_PER_CALL UNLIMITED -- 호출(구문분석, 실행, 추출)을 위해 허용되는 CPU 시간(1/100초)
CONNECT_TIME UNLIMITED -- 접속이 허용된 시간(분)
IDLE_TIME UNLIMITED -- 작업을 하지 않은 채로 접속이 허용된 시간(분)
SESSIONS_PER_USER UNLIMITED -- 세션당 허용된 유저 수
LOGICAL_READS_PER_SESSION UNLIMITED -- 세션이 디스크와 메모리에서 읽을 수 있는 블록 수(Block)
LOGICAL_READS_PER_CALL UNLIMITED -- SQL문을 수행하기 위해 세션이 릭을 수 있는 블록 수(Block)
PRIVATE_SGA UNLIMITED -- ※ shared sever를 사용할 때만 가능. shared pool에서 전용으로
사용할 수 있는 공간(Bytes)
COMPOSITE_LIMIT UNLIMITED -- 하나의 서비스 단위에서 사용할 수 있는 총 비용으로
CPU_PER_SESSION, CONNECT_TIME, LOGICAL_READS_PER_SESSION, PRIVATE_SGA에 가중치를 두어 계산(서비스)
PASSWORD_LIFE_TIME UNLIMITED -- 같은 패스워드를 사용할 수 있는 기간 지정(日)
PASSWORD_GRACE_TIME UNLIMITED -- 패스워드 라이프 타임이 지난 후 계정을 잠그기 전까지 경고 메세지
를 보여주는 기간(日)
PASSWORD_REUSE_MAX UNLIMITED -- 현재 사용하는 패스워드를 재사용하기 위해서는 패스워드를 몇 번
바꿔야 하는가
PASSWORD_REUSE_TIME UNLIMITED -- 현재 사용하는 패스워드를 보관하는 기간
FAILED_LOGIN_ATTEMPTS UNLIMITED -- 여기서 지정한 횟수를 초과한 로그인 실패가 있었을 경우 계정을
잠궈버린다
PASSWORD_LOCK_TIME UNLIMITED -- 로그인 실패로 계정이 잠겼을 때, 지정한 일자가 지나면 자동으로
잠금이 풀린다
PASSWORD_VERIFY_FUNCTION DEFAULT; -- 패스워드 복잡성 함수. $ORACLE_HOME/rdbms/admin/utlpwd.sql 이라는
스크립트를 수정하면 자신이 원하는 정책을 세울 수 있을 것이다.
※ 스크립트에는 펑션의 이름이 verify_function 로 지정되어 있다. 수정할 필요가 있다면 수정한다.
스크립트 마지막에 디폴트 프로필을 수정하는 부분이 있다. 적용하고 싶다면 적용하고 아니라면 삭제한다.
2. 프로파일 부여
SQL> ALTER USER any_user_name PROFILE any_profile_name;
혹은 생성시에 부여할 수도 있다.
SQL> CREATE USER any_user_name ... PROFILE any_profile_name ...;
3. 프로파일 수정
SQL> ALTER PROFILE any_profile_name LIMIT
...
any_profile_options
...;
수정된 프로파일은 현재 접속중인 세션에는 영향을 주지 않는다.
4. 프로파일 삭제
SQL> DROP PROFILE any_profile_name[ CASCADE];
해당 프로파일을 사용하는 유저가 있다면 cascade 옵션을 준다. 그렇게 해서 삭제된 유저의 프로파일은 서버의 기본 프로파일로 변경된다.
5. 프로파일 확인
DBA_USERS 의 PROFILE 컬럼, DBA_PROFILES 테이블의 PROFILE 컬럼을 조인한다.
[ 테이블 구조 ]
create table sample
(a number, b number, c number, d varchar2(10))
[ 컨트롤 화일 ? sample.ctl]
load data
infile sample.dat
replace
into table sample
fields terminated by ','
(a integer external,
b integer external,
c CONSTANT '100',
d char)
[ 외부 데이타 파일 - sample.dat ]
1,2,DATA
3,4,DATA2
5,6,DATA3
$ sqlldr hr/hr control=sample.ctl data=sample.dat
SQL> select * from sample;
A B C D
------- ----- ------ ------------
1 2 100 DATA
2 4 100 DATA2
2. 로드한 때의 날짜를 넣고 싶은 경우
[ 테이블 구조 ]
create table sysdate_table
(a number, b date, c varchar(10))
[ 컨트롤 화일 ]
load data
infile sysdate_table.dat
replace
into table sysdate_table
fields terminated by ','
(a integer external,
b sysdate,
c char(10))
[ 외부 데이타 화일 ]
111,STRINGS
222,STRINGS2
333,STRING3
[ 검색결과 ]
SQL> select * from sysdate_table
A B C
------- --------- ----------
111 13-MAY-94 STRING
222 13-MAY-94 STRING2
SYSDATE는 Conventional Path의 경우는 실행시에 삽입된 각각의 레코드 배열마다, Direct Path의 경우는 로드된각각의 레코드의 블록마다 사용된다. 새로운 값으로 변경된다.
[ 테이블 구조 ]
create table seq_table
(a varchar(10), b number, c varchar(10))
[ 컨트롤 화일 - seq_table.ctl ]
load data
infile seq_table.dat
replace
into table seq_table
fields terminated by ','
(a char,
b sequence(100,5),
c char)
[ 외부 데이타 파일 - seq_table.dat ]
1,a
2,b
3,c
[ 검색결과 ]
SQL> select * from seq_table
A B C
----- ---- --------
1 100 a
2 105 b
3 110 c
[ 테이블 구조 ]
create table pretb
(a varchar(10), b varchar(10), c varchar(10))
[ 컨트롤 화일 ? pretb.ctl]
load data
infile pretb.dat
preserve blanks
into table pretb
(a position(01:05) char,
b position(06:10) char,
c position(11:20) char)
[ 외부 데이타 파일 ? pretb.dat ]
12 4 67890 ab def hi
2 67890 ab def hi
[ 검색결과 ]
SQL> select * from pretb;
A B C
------- ------- ------------
12 4 67890 ab def hi
2 67890 ab def hi
SQL> select length(a), length(c) from pretb;
LENGTH(A) LENGTH(C)
--------- ----------
5 10
5 10
[ 테이블 구조 ]
create table null_table
(a varchar(10), b varchar(10), c varchar(10))
[ 컨트롤 화일 - null_table.ctl]
load data
infile null_table.dat
into table null_table
fields termintated by ','
trailing nullcols
(a char,
b char,
c char)
[ 외부 데이타 파일 - null_table.dat ]
1,aa,
2,bb,FF
3,cc,
[ 검색결과 ]
SQL> select * from null_table;
A B C
----- ----- -------
1 aa
2 bb FF
3 cc
trailing nullcols를 사용하지 않으면 1 레코드째와 3 레코드째가 데이타 에러가 된다.
[ 테이블 구조 ]
create table nulltb
(a varchar(10), b varchar(10), c varchar(10))
[ 컨트롤 파일 ? nulltb.ctl ]
load data
infile nulltb.dat
replace
into table nulltb
fields terminated by ','
(a char,
b char,
c char(10) nullif c = blanks)
[ 외부 데이타 파일 ? nulltb.dat ]
aa,bb, ,
11,22, ,
99,88,AA
00,00,BB
[ 검색결과 ]
SQL> select * from nulltb;
A B C
----- ------ ------
aa bb
11 22
99 88 AA
00 00 BB
7. POSITION 지정시 BLANK를 그대로 로드하고 싶은 경우
[ 테이블 구조 ]
create table nulltb2 (a varchar(10), b varchar(10), c date)
[ 컨트롤 화일 ]
load data
infile null3.dat
replace
preserve blanks
into table nulltb2
(a position(1:2) char,
b position(3:4) char nullif b = blanks,
c position(5:13) date "YY/MM/DD")
[ 외부 데이타 화일 ]
998892/11/11
94/12/12
[ 검색결과 ]
SQL>select * from nulltb2;
A B C
----- ----- ---------------
99 88 04/04/20
04/04/20
SQL> select length(a), length(b) from nulltb2;
LENGTH(A) LENGTH(B)
--------- ----------
2 2
2
8. BLANK가 들어가 있을 때 0을 입력하고 싶은 경우
[ 테이블 구조 ]
create table def2
(a varchar(10), b varchar(10), c number)
[ 컨트롤 화일 ]
load data
infile def2.dat
replace
into table def2
fields terminated by ','
(a char,
b char,
c integer external defaultif c = blanks)
[ 외부 데이타 화일 ]
11,11,123
22,22, ,
33,33, ,
44,44, ,
[ 검색결과 ]
SQL> select * from deft;
A B C
----- -------- -------
11 11 123
22 22 0
33 33 0
44 44 0
9. 40070건의 DATA가 들어 있는 우편번호 정보를 Oracle Table로 Loading 하시오.
과 같을 때 오라클 DB 속으로 1000건의 데이터를 Loading 하시오.
SQL> create directory BDUMP as '/u01/ora920/admin/ORA920/bdump'
organization external (
type oracle_loader
default directory BDUMP
access parameters (
records delimited by newline
)
location('alert_ORA920.log')
)
reject limit 1000;
SQL> select * from alertlog where text like '%ORA-%';
--------------------------------------------------------------------------------
ORA-00202: controlfile: '/u01/ora920/oradata/ora920/control01.ctl'
ORA-27037: unable to obtain file status
ORA-205 signalled during: ALTER DATABASE MOUNT...
ORA-1109 signalled during: ALTER DATABASE CLOSE NORMAL...
: 사용자가 요청한(select,DML 등) data block 복사본을 disk의 datafile 로 부터 읽어들여
저장하는 메모리 공간 (단위:block) >>> I/O성능향상을 위해, reuse(reduce disk I/O)
# redo log buffer
: server process에 의해 변경된 정보(redo information=redo entry)를 저장하는
메모리 공간 (1. PGA > 2. redo log buffer copy > 3. LGWR > 4. redo log file 기록)
목적-복구정보로 사용
# shared pool
: 사용자들에 의해 분석(parse)된 여러가지 정보를 보관하여 공유가능하게 만들어주는
메모리 공간 ( library(SQL분석정보) / dictionary cache )
# large pool
: 대용량 메모리 작업(Backup/recovery, batch load, parallel prcessing...)을 위해
설정하는 선택적 메모리 공간
(설정권장-미설정시 shared pool에서 발생 > 메모리부족현상, fragmentation 발생 가능..)
# CKPT
: checkpoint event(동기화 이벤트)가 발생하면
1) DBWn에 신호를 보내고 > dirty block을 datafile에 기록.
2) control file / datafile header 정보를 최신의 물리적 정보로 update 수행! (동기화정보) > 무결성 보장
# SMON
: 비정상적 종료(instance fail)가 발생한 경우 (정전, 잘못된 주소참조로 인한 OS강제종료, Device fail..)
> 미쳐 기록되지 못한 buffer 정보들을
- open중에 commit된정보는 recovery를(using redo log file) 수행하고(roll forward),
- open후에 uncommit 된 정보는 rollback을(using undo tablespace > undo segment) 수행함.
# PMON
: 비정상적으로 종료된 세션을 정리하는 프로세스. (강제로그아웃, session kill...)
cleanup > 1) rollback 2) lock 해제 3) resource 해제
# DBWn (n=0~19) > CPU 수와 연관
: buffer에 저장된 dirty block을 주기적으로 disk의 datafile에 기록하는 역할.
when? 1) checkpoint event발생 2) free buffer 부족 시
3) dirty block수가 임계치 도달 ...
# LGWR
: server process > redo log buffer > 주기적으로 LGWR 내려쓰기 > redo log file
when? commit, buffer 1/3 full, 매3초마다, 1MB이상의 redo발생, DBWn쓰기 직전
# ARCn (n=0~29)
# controlfile : 동기화정보 (for checkpoint) > 최신의 물리적 저장정보
> show parameter control_files, v$controlfile, v$controlfile_record_section
# data file : schema object repository (물리) vs tablespace(논리)
> dba_data_files, v$datafile vs dba_tablespaces, v$tablespace > dba_temp_files, v$tempfile
# redo log file : 복구정보 (for LGWR(주기적으로..), server process(수동 log switch))
> v$log, v$logfile, v$log_history
# parameter file : DB parameter 값을 저장한 파일
> show parameter XXX, v$parameter, v$spparameter
# archive log file : ARCn, log switch event발생
> v$archived_log, archive log list
# password file : sysdba 권한자들에 대한 목록 보유 (remote 접근 시 인증용으로 사용)
> v$pwfile_users
select empno, ename, job, sal from empl;
client > user process > server process
-----------------------------------------------------------------------------------------------------
col segment_type for a15
col tablespace_name for a15
set linesize 150
set pagesize 100
select segment_name, segment_type, tablespace_name
,count(extent_id), sum(blocks), sum(bytes)
from dba_extents
where owner=upper('&owner')
group by segment_name, segment_type, tablespace_name
/
set linesize 80
from &tablename
group by dbms_rowid.rowid_block_number(rowid)
/
CREATE OR REPLACE PROCEDURE Update_Test
( v_empno IN emp.empno%TYPE,
v_rate IN NUMBER )
IS
v_emp emp%ROWTYPE ;
BEGIN
UPDATE emp
SET sal = sal+(sal * (v_rate/100))
WHERE empno = v_empno ;
DBMS_OUTPUT.PUT_LINE( '*** Data Modify Successful *** ' );
SELECT empno, ename, sal
INTO v_emp.empno, v_emp.ename, v_emp.sal
FROM emp WHERE empno = v_empno ;
DBMS_OUTPUT.PUT_LINE( ' **** Modify Check **** ');
DBMS_OUTPUT.PUT_LINE( '1.Emp_no : ' || v_emp.empno );
DBMS_OUTPUT.PUT_LINE( '2.Emp_name : ' || v_emp.ename );
DBMS_OUTPUT.PUT_LINE( '3.Emp_salary : ' || v_emp.sal );
END ;
/
프로시저가 생성되었습니다.
===================================================================================
SQL> SET SERVEROUTPUT ON ; -- (DBMS_OUTPUT.PUT_LINE을 출력하기 위해 사용)
SQL> EXECUTE Update_Test(7900, -10);
데이터 수정 성공
*** Data Modify Successful ***
1.Emp_no : 7900
2.Emp_name : JAMES
3.Old_Emp_salary : 890 > 변경전 급여.
4.New_emp_salary : 855 > 변경후 급여.
-> 7900번 사원의 급여를 10% 인하했습니다.
sqlplus / as sysdba 접속
startup 이후에 파라미터 조회
show parameter audit
NAME TYPE VALUE
--------------------- ----------- ------------------------------------
audit_file_dest string /u01/app/oracle/admin/orcl/adump
audit_sys_operations boolean FALSE
audit_syslog_level string
audit_trail string NONE
spfile에 올려야 하기 때문에 DB를 내렸다 올려야 한다.
-static parameter입니다.-
alter system set audit_trail="DB" scope=spfile;
후에 내렸다 올린다.
startup이후 파라미터 조회를 해보면 DB로 수정되어있는 것을 볼수 있다.
1. Object 감사 수행
select owner, object_name, object_type, sel from dba_obj_audit_opts
where object_name='EMP' and owner='SCOTT';
save audit_obj.sql
audit select on scott.emp by session whenever successful;
Audit succeeded.<---이 메세지가 떠야 한다.
scott유저의 emp테이블에 성공적으로 select를 했을때 감사를 실시 한다.
audit_obj.sql를 실행하면 아래의 내용이 보인다.
OWNER OBJECT_NAME OBJECT_TYPE SEL
--------------- ------------------ ----------------- ------
SCOTT EMP TABLE S/-
select * from dba_obj_audit_opts
where object_name='EMP' and owner='SCOTT'
SEL
----
S/-
요렇게 나온다.
* dba_obj_audit_opts 는 object에 설정할 수 있는 각 audit option을 column으로 하고 있으며, 내용은 [A/S]/[A/S]의 형식을 갖는다. / 의 앞부분은 successful일 경우, 뒷부분은 not successful일 경우를 표시한다.
select count(*) from sys.aud$;
를 실행하면 0으로 나온다.
scott로 접속한다.
select * from emp where sal >3000;
조회를 한번 해보고~
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
------- ---------- ----------- ---------- ------------------ -------- ---------- --------
7839 KING PRESIDENT 1981-11-17 00:00:00 5000 10
로 다시 조회해본다.
그럼 count(*)가 1로 변한것을 알 수가 있다.
select os_username, username, timestamp, owner, obj_name, action_name, ses_actions, returncode
from dba_audit_object
OS_USERNAM USERNAME TIMESTAMP OWNER OBJ_NAME ACTION_NAM SES_ACTIONS RETURNCODE
---------- ---------- ------------------- ----- ---------- ---------- ------------------- ----------
oracle SCOTT 2009-12-24 17:58:38 SCOTT EMP SESSION RE ---------S------ 0
스크립트를 저장해둔다.
* returncode가 0인 경우는 SUCCESS 임을 의미한다.
* by session로 설정한 경우 audit를 설정한 경우 action_name 은 ‘SESSION REC’으로 표시된다.
* ses_actions columns은 총 13가지의 action(alter, audit, comment, delete, grant, index, insert,
lock, rename, select, update, reference, execute)에 대한 Audit 정보를 포함한다. 각 Action에 대해 모두 성공하였다면 ‘S’를 실패하였다면 ‘F’로 표현되며 성공과 실패가 모두 있었다면 ‘B’로 표현된다.
* by access로 설정한 경우 action_name 컬럼에 해당 action(예: delete, insert)등이 바로 기술된다.
select * from dba_priv_audit_opts;
조회를 하면 결과가 없다.
audit create session by scott;
성공했다는 메세지와 함께 다시 조회를 해보면 조회 내용이 나온다.
USER_NAME PROXY_NAME PRIVILEGE SUCCESS FAILURE
------------ ------------------ ----------------- ------------ ----------
SCOTT CREATE SESSION BY ACCESS BY ACCESS
그리고 나서 시간을 확인하고 관리자로 접속한다.
select os_username, username, timestamp, action_name, logoff_time, logoff_lread, logoff_pread
from dba_audit_session
where username='SCOTT';
OS_USERNAM USERNAME TIMESTAMP ACTION_NAM LOGOFF_TIME LOGOFF_LREAD LOGOFF_PREAD
---------- ---------- ------------------- ---------- ------------------- ------------ ------------
oracle SCOTT 2009-12-25 12:58:22 LOGOFF 2009-12-25 12:58:55 305 3
다시 원래 터미널에서 재 조회를 해보면 된다.
----- Statement Audit -----
존재하지 않는 오브젝트에 대한 구문을 실행시에 Audit Trail 작성
audit not exists by scott;
select * from dba_stmt_audit_opts;
USER_NAME PROXY_NAME AUDIT_OPTION SUCCESS FAILURE
------------ --------------- ----------------- ---------- ----------
SCOTT CREATE SESSION BY ACCESS BY ACCESS
SCOTT NOT EXISTS BY ACCESS BY ACCESS
grant select on not_exist_table to tester;
관리자로 접속한 후에
select os_username,username,timestamp,obj_name,action_name,obj_privilege, grantee
from dba_audit_statement;
OS_USERNAM USERNAME TIMESTAMP OBJ_NAME ACTION_NAM OBJ_PRIVILEGE GRANTEE
---------- ---------- ------------------- ---------- ---------- ---------------- ------------------------------
oracle SCOTT 2009-12-25 13:53:13 NOT_EXIST_ GRANT OBJE ---------Y------ TESTER
TABLE CT
위의 결과에서는 어떤 구문을 실행했을 때 Auditing 되었는지 정확히 알 수가 없고, Object Audit 에서 볼 수 있듯이 어떤 데이터를 조회했는지 알 수가 없다.
10g부터 추가된 DB_Extended 기능을 사용해 본다.
conn /as sysdba
alter system set audit_trail=db_extended scope=spfile;
System altered.
shutdown immediate
startup
show parameter audit_trail
NAME TYPE VALUE
---------------------- ----------- ---------------
audit_trail string DB_EXTENDED
select owner, object_type, object_name, ins from dba_obj_audit_opts
where owner = 'SCOTT' and object_name = 'EMP';
OWNER OBJECT_TYPE OBJECT_NAME INS
----- ----------------- ------------ -----
SCOTT TABLE EMP A/A
Name Null? Type
----- -------- --------------------------------------------------------------------------
OS_USERNAME VARCHAR2(255)
USERNAME VARCHAR2(30)
USERHOST VARCHAR2(128)
TERMINAL VARCHAR2(255)
TIMESTAMP DATE
OWNER VARCHAR2(30)
OBJ_NAME VARCHAR2(128)
ACTION_NAME VARCHAR2(28)
NEW_OWNER VARCHAR2(30)
NEW_NAME VARCHAR2(128)
SES_ACTIONS VARCHAR2(19)
COMMENT_TEXT VARCHAR2(4000)
SESSIONID NOT NULL NUMBER
ENTRYID NOT NULL NUMBER
STATEMENTID NOT NULL NUMBER
RETURNCODE NOT NULL NUMBER
PRIV_USED VARCHAR2(40)
CLIENT_ID VARCHAR2(64)
ECONTEXT_ID VARCHAR2(64)
SESSION_CPU NUMBER
EXTENDED_TIMESTAM TIMESTAMP(6) WITH TIME ZONE
PROXY_SESSIONI NUMBER
GLOBAL_UID VARCHAR2(32)
INSTANCE_NUMB NUMBER
OS_PROCESS VARCHAR2(16)
TRANSACTIONID RAW(8)
SCN NUMBER
SQL_BIND NVARCHAR2(2000)
SQL_TEXT NVARCHAR2(2000)
select username, owner, obj_name, ACTION_NAME, SES_ACTIONS, RETURNCODE, TIMESTAMP, SQL_BIND, SQL_TEXT
from dba_audit_object;
USERNAME OWNER OBJ_NAME ACTION_NAME SES_ACTIONS RETURNCODE TIMESTAMP SQL_BIND SQL_TEXT
---------- ----- ---------- --------------- ------------------- ---------- ------------------- --------------- ---------------
SCOTT SCOTT EMP SESSION REC ---------S------ 0 2009-12-24 17:58:38
variable empno number;
variable ename varchar2(8);
:empno := 9999;
:ename := 'TESTER';
end;
/
commit후에 다시 조회를 해보면 SQL_BIND, SQL_TEXT의 내용을 볼 수가 있다.
Audit Trail이 쌓이는 SYS.AUD$ 테이블은 SYSTEM 테이블스페이스 생성된다.
그러므로 SYS.AUD$ 테이블에 데이터가 쌓임으로써 SYSTEM 테이블에 대하여 경합 등 부담을 줄 수 있다.
예를 들어, CREATE SESSION에 대한 AUDITING을 수행할 때 세션의 사용량에 따라 엄청난 데이터가 축척될 수 있다.
그러므로 불필요한 AUDIT의 사용은 데이터베이스의 성능을 저하시킬 수 있다.
그러므로 불필요한 Audit기능은 제한하고, Audit하는 기간 동안 SYS.AUD$ 테이블의 크기를 적절히 유지하도록 해야한다.
?? Archiving Audit Trail Information
?? Reducing the Size of the Audit Trail
DELETE FROM SYS.AUD$;
INSERT INTO table SELECT … FROM SYS.AUD$ …
sys/sys as sysdba
file=aud.dmp
tables=aud$;
차례대로 입력하면 백업을 시작한다.
: Archiving과 Purging을 이용한 관리
1. SYS.AUD$ 에 대한 백업을 수행한다. - Export 등
2. sys 유저로 접속한다. ? 관리자에 의한 수행
3. TRUNCATE TABLE SYS.AUD$; (HWM 의 이동으로 extent할당을 해제하여 테이블 내 공간을 줄임.)
4. Audit Trail Record가 많이 생성되면 1번부터 재수행한다.
CREATE TABLE emp_audit (
old_empno NUMBER(4),
old_ename VARCHAR2(10),
old_job VARCHAR2(9),
old_mgr NUMBER(4),
old_hiredate DATE,
old_sal NUMBER(7,2),
old_comm NUMBER(7,2),
old_deptno NUMBER(2),
new_empno NUMBER(4),
new_ename VARCHAR2(10),
new_job VARCHAR2(9),
new_mgr NUMBER(4),
new_hiredate DATE,
new_sal NUMBER(7,2),
new_comm NUMBER(7,2),
new_deptno NUMBER(2),
changed_by VARCHAR2(8),
change_type CHAR(1),
timestamp DATE )
CREATE OR REPLACE TRIGGER LogEmpChanges
BEFORE INSERT OR DELETE OR UPDATE ON scott.emp
FOR EACH ROW
DECLARE
v_ChangeType CHAR(1);
BEGIN
/* Use 'I' for an INSERT, 'D' for DELETE, and 'U' for UPDATE. */
IF INSERTING THEN
v_ChangeType := 'I';
ELSIF UPDATING THEN
v_ChangeType := 'U';
ELSE
v_ChangeType := 'D';
END IF;
INSERT INTO emp_audit (
change_type, changed_by, timestamp, old_empno,
old_ename, old_job, old_mgr, old_hiredate, old_sal,
old_comm, old_deptno, new_empno, new_ename, new_job,
new_mgr, new_hiredate, new_sal, new_comm, new_deptno)
VALUES (
v_ChangeType, USER, SYSDATE, :old.empno, :old.ename,
:old.job, :old.mgr, :old.hiredate, :old.sal, :old.comm,
:old.deptno, :new.empno, :new.ename, :new.job, :new.mgr,
:new.hiredate, :new.sal, :new.comm, :new.deptno);
END LogEmpChanges;
트리거를 생성한다.
scott로 접속
INSERT INTO emp VALUES ( 9999, 'TESTER', 'CLERK', 7782, SYSDATE, 1000, 0, 10);
commit;
UPDATE emp SET comm = 300 WHERE empno = 9999;
commit;
DELETE FROM emp WHERE empno = 9999;
commit;
관리자로 접속
CHANGED_BY, CHANGE_TYPE, TIMESTAMP
FROM EMP_AUDIT;
OLD_EMPNO OLD_ENAME OLD_COMM NEW_EMPNO NEW_ENAME NEW_COMM CHANGED_ C TIMESTAMP
---------- ---------- ---------- ---------- ---------- ---------- -------- - -------------------
9999 TESTER 0 SCOTT I 2008-12-26 13:22:19
9999 TESTER 0 9999 TESTER 300 SCOTT U 2008-12-26 13:22:25
9999 TESTER 300 SCOTT D 2008-12-26 13:22:31
위와 같은 소스를 자동 생성해주는 샘플 Package를 생성하여 응용할 수 있다. [첨부파일]
해당 테이블의 정보를 추출하여 audit trail record를 담을 테이블과 이벤트를 처리할 트리거를 자동생성하고 제거할 수 있는 패키지이다. 구문을 자동 생성하고, 실행시키는 루틴을 포함시켜 놓았다. 오라클의 제공하는 Audit 기능을 대체할 수 있도록 응용해 보기 바란다.
-----audit_package.sql-----
--Trigger 를 이용한 DML Auditing - Package Name : AUDIT_UTIL
CREATE OR REPLACE PACKAGE AUDIT_UTIL
IS
-- AUDIT 테이블 생성
PROCEDURE create_audit_table(
dest_table_owner IN VARCHAR2,
dest_table_name IN VARCHAR2,
audit_table_name IN VARCHAR2 DEFAULT '',
tablespace_name IN VARCHAR2 DEFAULT 'SYSTEM');
-- TRIGGER 생성
PROCEDURE create_audit_trigger(
audit_table_name IN VARCHAR2,
dest_table_owner IN VARCHAR2,
dest_table_name IN VARCHAR2);
-- DML AUDIT 를 위한 테이블 및 트리거 자동 생성
PROCEDURE create_dml_audit(
dest_table_owner IN VARCHAR2,
dest_table_name IN VARCHAR2,
audit_table_name IN VARCHAR2 DEFAULT '',
tablespace_name IN VARCHAR2 DEFAULT 'SYSTEM');
-- DML AUDIT 관련 테이블 및 트리거 제거
PROCEDURE remove_dml_audit(
audit_table_name IN VARCHAR2,
audit_trigger_name IN VARCHAR2 DEFAULT '');
-- ADUIT TABLE 내 데이터 삭제 (날짜별 이전 데이터 삭제)
PROCEDURE delete_auditing_values(
audit_table_name IN VARCHAR2,
start_date IN DATE,
end_date IN DATE DEFAULT NULL);
-- ADUIT TABLE 내 데이터 삭제 (지정 일수 이전 데이터 삭제)
PROCEDURE delete_auditing_values(
audit_table_name IN VARCHAR2,
days IN NUMBER);
END AUDIT_UTIL;
/
CREATE OR REPLACE PACKAGE BODY AUDIT_UTIL
IS
-- 0. DDL 실행 프로시져(PRIVATE)
PROCEDURE exec_ddl(statement IN VARCHAR2)
IS
v_statment VARCHAR2(4000);
v_cid INTEGER;
v_ret INTEGER;
BEGIN
v_statment := R-PLACE(statement, CHR(10), '');
v_cid := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(C => v_cid,
STATEMENT => v_statment,
LANGUAGE_FLAG => DBMS_SQL.NATIVE);
--v_ret := DBMS_SQL.EXECUTE(v_cid);
DBMS_SQL.CLOSE_CURSOR(v_cid);
END exec_ddl;
-- 0. DML 실행 프로시져(PRIVATE)
PROCEDURE exec_dml(statement IN VARCHAR2)
IS
v_statment VARCHAR2(4000);
v_cid INTEGER;
v_ret INTEGER;
BEGIN
v_statment := R-PLACE(statement, CHR(10), '');
v_cid := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(C => v_cid,
STATEMENT => v_statment,
LANGUAGE_FLAG => DBMS_SQL.NATIVE);
v_ret := DBMS_SQL.EXECUTE(v_cid);
DBMS_SQL.CLOSE_CURSOR(v_cid);
END exec_dml;
-- 1. AUDIT 테이블 생성 PROCEDURE : CREATE_AUDIT_TABLE (only SYS OR SYSTEM USER)
PROCEDURE create_audit_table (
dest_table_owner in VARCHAR2,
dest_table_name in VARCHAR2,
audit_table_name in VARCHAR2 DEFAULT '',
tablespace_name in VARCHAR2 DEFAULT 'SYSTEM')
IS
CURSOR c_table_columns IS
SELECT column_name, data_type, data_length, data_precision, data_scale
FROM dba_tab_columns
WHERE owner = dest_table_owner
AND table_name = dest_table_name;
v_ddl VARCHAR2(4000);
v_audit_table_name VARCHAR2(100);
BEGIN
IF (dest_table_owner IS NULL ) OR (dest_table_name IS NULL) THEN
DBMS_OUTPUT.PUT_LINE('No Values in Owner or Table_name');
END IF;
IF (audit_table_name IS NULL) THEN
v_audit_table_name := dest_table_name || '_AUDIT';
ELSE
v_audit_table_name := audit_table_name;
END IF;
-- Table DDL 문
v_ddl := 'CREATE TABLE ' || v_audit_table_name || ' (' || chr(10);
FOR v_col_rec IN c_table_columns LOOP
IF (c_table_columns%NOTFOUND) THEN
DBMS_OUTPUT.PUT_LINE('TABLE NOT FOUND');
END IF;
CASE
WHEN v_col_rec.data_type IN ('VARCHAR2', 'NVARCHAR2', 'CHAR', 'NCHAR') THEN
v_ddl := v_ddl || ' old_' || v_col_rec.column_name || ' '
|| v_col_rec.data_type ||'(' || v_col_rec.data_length || ')';
WHEN v_col_rec.data_type = 'NUMBER' THEN
v_ddl := v_ddl || ' old_' || v_col_rec.column_name || ' ' || v_col_rec.data_type;
IF (v_col_rec.data_precision IS NOT NULL) THEN
v_ddl := v_ddl || '(' || v_col_rec.data_precision;
IF (v_col_rec.data_scale IS NOT NULL) THEN
v_ddl := v_ddl || ',' || v_col_rec.data_scale;
END IF;
v_ddl := v_ddl || ')';
END IF;
ELSE
v_ddl := v_ddl || ' old_' || v_col_rec.column_name || ' ' || v_col_rec.data_type;
END CASE;
v_ddl := v_ddl || ',' || CHR(10);
END LOOP;
FOR v_col_rec IN c_table_columns LOOP
IF (c_table_columns%NOTFOUND) THEN
DBMS_OUTPUT.PUT_LINE('TABLE NOT FOUND');
END IF;
CASE
WHEN v_col_rec.data_type IN ('VARCHAR2', 'NVARCHAR2', 'CHAR', 'NCHAR') THEN
v_ddl := v_ddl || ' new_' || v_col_rec.column_name || ' '
|| v_col_rec.data_type ||'(' || v_col_rec.data_length || ')';
WHEN v_col_rec.data_type = 'NUMBER' THEN
v_ddl := v_ddl || ' new_' || v_col_rec.column_name || ' ' || v_col_rec.data_type;
IF (v_col_rec.data_precision IS NOT NULL) THEN
v_ddl := v_ddl || '(' || v_col_rec.data_precision;
IF (v_col_rec.data_scale IS NOT NULL) THEN
v_ddl := v_ddl || ',' || v_col_rec.data_scale;
END IF;
v_ddl := v_ddl || ')';
END IF;
ELSE
v_ddl := v_ddl || ' new_' || v_col_rec.column_name || ' ' || v_col_rec.data_type;
END CASE;
v_ddl := v_ddl || ',' || CHR(10);
END LOOP;
v_ddl := v_ddl || ' changed_by VARCHAR2(8),' || CHR(10);
v_ddl := v_ddl || ' change_type CHAR(1),' || CHR(10);
v_ddl := v_ddl || ' timestamp DATE' || CHR(10) || ') TABLESPACE ' || tablespace_name;
exec_ddl(v_ddl);
END create_audit_table;
-- 2. TRIGGER 생성 PROCEDURE : CREATE_AUDIT_TRIGGER
PROCEDURE create_audit_trigger(
audit_table_name IN VARCHAR2,
dest_table_owner IN VARCHAR2,
dest_table_name IN VARCHAR2)
IS
CURSOR c_table_columns IS
SELECT rownum, column_name FROM dba_tab_columns
WHERE owner = USER
AND table_name = audit_table_name;
v_audit_table_name VARCHAR2(100);
v_st VARCHAR2(4000);
BEGIN
v_audit_table_name := audit_table_name;
v_st := 'CREATE OR REPLACE TRIGGER TR_' || v_audit_table_name|| CHR(10)
|| ' BEFORE INSERT OR DELETE OR UPDATE ON ' || dest_table_owner || '.' || dest_table_name || CHR(10)
|| ' FOR EACH ROW '|| CHR(10)
|| 'DECLARE' || CHR(10)
|| ' v_ChangeType CHAR(1); ' || CHR(10)
|| 'BEGIN ' || CHR(10)
|| ' IF INSERTING THEN v_ChangeType := ''I''; ' || CHR(10)
|| ' ELSIF UPDATING THEN v_ChangeType := ''U''; ' || CHR(10)
|| ' ELSE v_ChangeType := ''D''; ' || CHR(10)
|| ' END IF; ' || CHR(10)
|| ' INSERT INTO ' || v_audit_table_name || '(';
FOR v_col_rec IN c_table_columns LOOP
IF (v_col_rec.rownum > 1) THEN
v_st := v_st || ', ';
END IF;
v_st := v_st || v_col_rec.column_name;
END LOOP;
v_st := v_st || ') ' || CHR(10) || ' VALUES (';
FOR v_col_rec IN c_table_columns LOOP
IF (v_col_rec.rownum > 1) THEN
v_st := v_st || ', ';
END IF;
CASE SUBSTR(v_col_rec.column_name, 1, 3)
WHEN 'OLD' THEN
v_st := v_st || REPLACE(v_col_rec.column_name, 'OLD_', ':OLD.');
WHEN 'NEW' THEN
v_st := v_st || REPLACE(v_col_rec.column_name, 'NEW_', ':NEW.');
ELSE
IF (v_col_rec.column_name = 'CHANGED_BY') THEN
v_st := v_st || 'USER';
ELSIF (v_col_rec.column_name = 'CHANGE_TYPE') THEN
v_st := v_st || 'v_ChangeType';
ELSIF (v_col_rec.column_name = 'TIMESTAMP') THEN
v_st := v_st || 'SYSDATE';
END IF;
END CASE;
END LOOP;
v_st := v_st || '); ' || CHR(10)
|| 'END TR_' || v_audit_table_name || ';';
exec_ddl(v_st);
END create_audit_trigger;
-- 3. DML AUDIT 를 위한 테이블 및 트리거 자동 생성 PROCEDURE : CREATE_DML_AUDIT
PROCEDURE create_dml_audit(
dest_table_owner in VARCHAR2,
dest_table_name in VARCHAR2,
audit_table_name in VARCHAR2 DEFAULT '',
tablespace_name in VARCHAR2 DEFAULT 'SYSTEM')
IS
v_audit_table_name VARCHAR2(100);
v_dest_table_owner VARCHAR2(100);
V_dest_table_name VARCHAR2(100);
BEGIN
v_dest_table_owner := UPPER(dest_table_owner);
v_dest_table_name := UPPER(dest_table_name);
IF (audit_table_name IS NULL) THEN
v_audit_table_name := UPPER(dest_table_name) || '_AUDIT';
ELSE
v_audit_table_name := UPPER(audit_table_name);
END IF;
CREATE_AUDIT_TABLE(v_dest_table_owner, v_dest_table_name, v_audit_table_name, tablespace_name);
CREATE_AUDIT_TRIGGER(v_audit_table_name, v_dest_table_owner, v_dest_table_name);
END create_dml_audit;
-- 4. DML AUDIT 관련 테이블 및 트리거 제거 PROCEDURE : MAKE_DML_AUDIT
PROCEDURE remove_dml_audit(
audit_table_name IN VARCHAR2,
audit_trigger_name IN VARCHAR2 DEFAULT '')
IS
v_c INTEGER;
v_st VARCHAR2(4000);
v_tr VARCHAR2(100);
BEGIN
v_st := 'DROP TABLE ' || audit_table_name;
exec_ddl(v_st);
IF (audit_trigger_name IS NULL) THEN
v_tr := 'TR_' || audit_table_name;
ELSE
v_tr := audit_trigger_name;
END IF;
v_st := 'DROP TRIGGER ' || v_tr;
exec_ddl(v_st);
END remove_dml_audit;
-- 5. ADUIT TABLE 내 데이터 삭제 PROCEDURE : DELETE_AUDITING_VALUES
PROCEDURE delete_auditing_values(
audit_table_name IN VARCHAR2,
start_date IN DATE,
end_date IN DATE DEFAULT NULL)
IS
v_st VARCHAR2(4000);
BEGIN
v_st := 'DELETE FROM' || audit_table_name;
IF (end_date IS NULL) THEN
v_st := v_st || ' WHERE TIMESTAMP < TO_DATE('''
|| TO_CHAR(start_date, 'YYYY-MM-DD HH24:MI:SS')
|| ''', ''fmYYYY-MM-DD HH24:MI:SS'')';
ELSE
v_st := v_st || ' WHERE TIMESTAMP BETWEEN TO_DATE('''
|| TO_CHAR(start_date, 'YYYY-MM-DD HH24:MI:SS')
|| ''', ''fmYYYY-MM-DD HH24:MI:SS'') AND TO_DATE('''
|| TO_CHAR(end_date, 'fmYYYY-MM-DD HH24:MI:SS')
|| ''', ''fmYYYY-MM-DD HH24:MI:SS'')';
END IF;
exec_dml(v_st);
COMMIT;
END delete_auditing_values;
PROCEDURE delete_auditing_values(
audit_table_name IN VARCHAR2,
days IN NUMBER)
IS
v_st VARCHAR2(4000);
v_last_date DATE;
BEGIN
v_last_date := SYSDATE - days;
v_st := 'DELETE FROM' || audit_table_name
|| ' WHERE TIMESTAMP < TO_DATE('''
|| TO_CHAR(v_last_date, 'YYYY-MM-DD HH24:MI:SS')
|| ''', ''fmYYYY-MM-DD HH24:MI:SS'')';
exec_dml(v_st);
COMMIT;
END delete_auditing_values;
END AUDIT_UTIL;
/
------------------------------------------------------------------------------------
1. 실행방법 ( AUDIT 용 TABLE 및 TRIGGER 생성)
exec make_dml_audit (dest_table_owner, dest_table_name, \
audit_table_name(default ''), tablespace_name(default 'SYSTEM');
EXAMPLE 1
- exec make_dml_audit('SCOTT', 'EMP');
EXAMPLE 2
- exec make_dml_audit('SCOTT', 'EMP', 'EMP_AUDIT', 'USERS');
확인 : DML 작업 이후 audit_table_name 조회
EXAMPLE - SELECT * FROM EMP_AUDIT;
EXAMPLE 1
- exec delete_auditing_values('EMP_AUDIT', TO_DATE('2007-08-01 18:00:00', 'fmYYYY-MM-DD HH24:MI:SS');
EXAMPLE 2
- exec delete_auditing_values('EMP_AUDIT', TO_DATE('2007-08-01 00:00:00', 'fmYYYY-MM-DD HH24:MI:SS'), TO_DATE('2007-08-01 18:00:00', 'fmYYYY-MM-DD HH24:MI:SS'));
EXAMPLE 3
- exec delete_auditing_values('EMP_AUDIT', 1); -- 1일 이전 데이터 삭제
exec remove_dml_audit (audit_table_name, audit_trigger_name(default ''));
EXAMPLE - exec remove_dml_audit('EMP_AUDIT');
-- Test : SCOTT.EMP 에 대한 DML Auditing
exec make_dml_audit('SCOTT', 'EMP', 'EMP_AUDIT', 'USERS');
select table_name from dba_tables where trigger_name like '%_AUDIT'
select trigger_name from dba_triggers where trigger_name like 'TR_%'
connect scott/tiger
INSERT INTO emp VALUES ( 9999, 'TESTER', 'CLERK', 7782, SYSDATE, 1000, 0, 10);
COMMIT;
UPDATE emp SET comm = 300 WHERE empno = 9999;
COMMIT;
DELETE FROM emp WHERE empno = 9999;
COMMIT;
connect /as sysdba
SELECT OLD_EMPNO, OLD_ENAME, OLD_COMM, NEW_EMPNO, NEW_ENAME, NEW_COMM, CHANGED_BY, CHANGE_TYPE,
TIMESTAMP FROM EMP_AUDIT;
OLD_EMPNO OLD_ENAME OLD_COMM NEW_EMPNO NEW_ENAME NEW_COMM CHANGED_BY CH TIMESTAMP
---------- ---------- ---------- ---------- ---------- ---------- ---------------- -- ---------
9999 TESTER 0 SCOTT I 01-AUG-07
9999 TESTER 0 9999 TESTER 300 SCOTT U 01-AUG-07
9999 TESTER 300 SCOTT D 01-AUG-07
-- 일정 기간에 대한 Audit Trail Reocords 삭제
alter session set nls_date_format = 'yyyy-mm-dd hh24:mi:ss';
exec delete_auditing_values('EMP_AUDIT', TO_DATE('2007-08-01 18:00:00', 'fmYYYY-MM-DD HH24:MI:SS'));
exec delete_auditing_values('EMP_AUDIT', TO_DATE('2007-08-01 00:00:00', 'fmYYYY-MM-DD HH24:MI:SS'),
TO_DATE('2007-08-01 18:00:00', 'fmYYYY-MM-DD HH24:MI:SS'));
exec delete_auditing_values('EMP_AUDIT', 0); -- 현재 이전 삭제(전체 삭제)
-- dbms_job 을 이용하여 자동 삭제 스케줄링
VARIABLE job_no NUMBER;
VARIABLE inst_no NUMBER;
begin
select instance_number into :inst_no from v$instance;
dbms_job.submit(:job_no, 'AUDIT_UTIL(''EMP_AUDIT'', 0);', trunc(sysdate+1,'HH'), 'trunc(SYSDATE+1,''HH'')', TRUE, :inst_no);
commit;
end;
/
print :job_no;
exec dbms_job.broken(:job_no, TRUE);
exec dbms_job.remove(:job_no);
-- Audit Trail Table 제거
exec remove_dml_audit('EMP_AUDIT');
----- Value-Based Auditing -----
(터미널1: system)---------------------------------
$ sqlplus system/oracle
create table audit_employees
(username varchar2(150)
,mod_date date
,ipaddr varchar2(30)
,mod_conts varchar2(2000))
tablespace example ;
AFTER UPDATE OF salary
ON hr.employees
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
BEGIN
IF :old.salary != :new.salary THEN
INSERT INTO system.audit_employees
VALUES (sys_context('userenv','os_user'), sysdate,
sys_context('userenv','ip_address'),
:new.employee_id ||
' salary changed from '||:old.salary||
' to '||:new.salary);
END IF;
END;
/
select * from system.audit_employees ;
(터미널2: hr)------------------------------------
update hr.employees
set salary= 3000
where employee_id= 198 ;
commit ;
(터미널1: system)---------------------------------
ALTER SESSION SET nls_date_format='YYYY/MM/DD HH24:MI:SS' ;
select * from system.audit_employees ;
select * from hr.employees
where employee_id = 198 ;
NAME TYPE VALUE
----------------- ----------- ---------
audit_trail string NONE
DBMS_FGA.ADD_POLICY(object_schema => 'SCOTT',
object_name => 'EMP',
policy_name => 'POL_SCOTT_EMP',
audit_condition => 'sal > 3000',
enable => TRUE,
statement_types => 'SELECT, INSERT',
audit_trail => DBMS_FGA.DB_EXTENDED);
END;
FROM dba_audit_policies;
OBJECT_SCH OBJECT_NAM POLICY_NAME POLICY_TEXT POLICY_COLUMN ENA
------------- ------------- ------------------ --------------- --------------------- ----
SCOTT EMP POL_SCOTT_EMP sal > 3000 YES
SELECT timestamp, object_name, scn, sql_text, sql_bind
FROM dba_fga_audit_trail;
no rows selected
var ename varchar2(10);
begin
:empno := 1234;
:ename := 'ocmkorea';
end;
/
insert into emp values (:empno, :ename, 'MANAGER', 7499, SYSDATE, 3100, '', 20);
select * from emp;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- ------------------- ---------- ---------- -------
8888 TESTER2 SALESMAN 7499 2008-12-26 13:41:40 3200 10 30
1234 ocmkorea MANAGER 7499 2008-12-26 13:45:36 3100 20
7369 SMITH CLERK 7902 1980-12-17 00:00:00 800 20
7499 ALLEN SALESMAN 7698 1981-02-20 00:00:00 1600 300 30
7521 WARD SALESMAN 7698 1981-02-22 00:00:00 1250 500 30
7566 JONES MANAGER 7839 1981-04-02 00:00:00 2975 20
7654 MARTIN SALESMAN 7698 1981-09-28 00:00:00 1250 1400 30
7698 BLAKE MANAGER 7839 1981-05-01 00:00:00 2850 30
7782 CLARK MANAGER 7839 1981-06-09 00:00:00 2450 10
7788 SCOTT ANALYST 7566 1987-04-19 00:00:00 3000 20
7839 KING PRESIDENT 1981-11-17 00:00:00 5000 10
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- ------------------- ---------- ---------- ------- 7844 TURNER SALESMAN 7698 1981-09-08 00:00:00 1500 0 30
7876 ADAMS CLERK 7788 1987-05-23 00:00:00 1100 20
7900 JAMES CLERK 7698 1981-12-03 00:00:00 950 30
7902 FORD ANALYST 7566 1981-12-03 00:00:00 3000 20
7934 MILLER CLERK 7782 1982-01-23 00:00:00 1300 10
insert into emp values (7777, 'OCMKOREA2', 'SALESMAN', 7499, SYSDATE, 3200, 10, 30);
delete from emp where empno = 7777; -- 정책에 포함되지 않은 구문이므로 기록되지 않음.
conn /as sysdba
from dba_fga_audit_trail;
------------------- ----------------------------------------------------------------------
SCN
----------
SQL_BIND
-----------------------------------------------------------------------------------------
SQL_TEXT
-----------------------------------------------------------------------------------------
2008-12-26 13:46:07 EMP
0
insert into emp values (7777, 'OCMKOREA2', 'SALESMAN', 7499, SYSDATE, 3200, 10, 30)
* Oracle Database 10g 부터 statement_types과 audit_trail이 추가되었다. Oracle 9i Database에서 SELECT 문만 auditing이 가능했지만 Oracle Database 10g 에서는 INSERT, DELETE, UPDATE, MERGE 에 대해서도 가능하다. 또한 audit_trail 파라메터에 DBMS_FGA.DB_EXTENDED로 설정하므로 init parameter 의 audit_trail 파라메터와 무관하게 FGA 가 설정만으로 수행된 구문과 바인드 정보를 볼 수 있다.
[Oracle Database 10g FGA 예제1 ? AUDIT_COLUMN_OPTS]
conn /as sysdba
BEGIN
DBMS_FGA.DROP_POLICY(object_schema => 'SCOTT',
object_name => 'EMP',
policy_name => 'POL_SCOTT_EMP');
END;
DBMS_FGA.ADD_POLICY(object_schema => 'SCOTT',
object_name => 'EMP',
policy_name => 'POL_SCOTT_EMP1',
audit_column => 'empno, sal, comm',
enable => TRUE,
audit_column_opts => DBMS_FGA.ANY_COLUMNS);
END;
from dba_fga_audit_trail;
conn scott/tiger
EMPNO ENAME
---------- ----------
1234 ocmkorea
7369 SMITH
7566 JONES
7788 SCOTT
7876 ADAMS
7902 FORD
select empno, sal from emp where sal > 3000;
EMPNO SAL
---------- ----------
8888 3200
1234 3100
7839 5000
select ename, job from emp where job > 'MANAGER';
ENAME JOB
---------- ---------
TESTER2 SALESMAN
ALLEN SALESMAN
WARD SALESMAN
MARTIN SALESMAN
KING PRESIDENT
TURNER SALESMAN
select empno, sal, comm from emp where deptno = 30;
EMPNO SAL COMM
---------- ---------- ----------
8888 3200 10
7499 1600 300
7521 1250 500
7654 1250 1400
7698 2850
7844 1500 0
7900 950
conn /as sysdba
from dba_fga_audit_trail;
TIMESTAMP OBJECT_NAME SCN SQL_BIND SQL_TEXT
------------------- -------------------- ---------- -------------------- ------------------2008-12-26 13:56:38 EMP 599796 select empno, ename from emp where deptno = 20
2008-12-26 13:56:42 EMP 599800 select empno, sal from emp where sal > 3000
2008-12-26 13:56:50 EMP 599803 select empno, sal, comm from emp where deptno = 30
SQL> -- audit_column_opts 값이 DBMS_FGA.ANY_COLUMNS으로 설정했을 경우 audit_column에 나열된 Column 중에 1개라도 포함이 되어 있다면 Audit Trail이 기록된다. 나열된 컬럼들 중에 없는 경우는 기록되지 않는다.
BEGIN
DBMS_FGA.DROP_POLICY(object_schema => 'SCOTT',
object_name => 'EMP',
policy_name => 'POL_SCOTT_EMP1');
END;
DBMS_FGA.ADD_POLICY(object_schema => 'SCOTT',
object_name => 'EMP',
policy_name => 'POL_SCOTT_EMP2',
audit_column => 'empno, sal, comm',
enable => TRUE,
audit_column_opts => DBMS_FGA.ALL_COLUMNS);
END;
EMPNO ENAME
---------- ----------
1234 ocmkorea
7369 SMITH
7566 JONES
7788 SCOTT
7876 ADAMS
7902 FORD
select empno, sal from emp where sal > 3000;
EMPNO SAL
---------- ----------
8888 3200
1234 3100
7839 5000
select ename, job from emp where job > 'MANAGER';
ENAME JOB
---------- ---------
TESTER2 SALESMAN
ALLEN SALESMAN
WARD SALESMAN
MARTIN SALESMAN
KING PRESIDENT
TURNER SALESMAN
select empno, sal, comm from emp where deptno = 30; -- policy에 부합되는 조회
EMPNO SAL COMM
---------- ---------- ----------
8888 3200 10
7499 1600 300
7521 1250 500
7654 1250 1400
7698 2850
7844 1500 0
7900 950
conn /as sysdba
from dba_fga_audit_trail;
TIMESTAMP OBJECT_NAME SCN SQL_BIND SQL_TEXT
------------------- -------------------- ---------- -------------------- ---------------
2008-12-26 13:59:02 EMP 599886 select empno, sal, comm from emp where deptno = 30
-- 위와 같이 audit_column_opts 를 DBMS_FGA.ALL_COLUMN으로 설정한 경우, audit_column 에 나열한 컬럼이 모두 조회 되는 구문에서만
Audit Trail 이 기록된다.
분석된 결과를 OS상의 파일로 저장
초기화 파라미터를 설정해야 한다.
show parameter utl_file_dir
alter system set utl_file_dir='/home/oracle/logminer' scope=spfile;
logminer라는 폴더는 미리 생성되어있어야 한다.
그리고 DB를 재시작해준다.
conn system/oracle
update scott.emp set sal=sal*1.5;
commit;
logminer를 활용하기 위해서는 패키지가 필요하다.
DBMS_LOGMNR, DBMS_LOGMNR_D
+ DBMS_LOGMNR_D
SQL>@?/rdbms/admin/dbmslmd.sql
이 명령으로 설치 해준다. 어지간하면 다 설치 되어있을것이다.
패키지 설치 후에 다음 명령어를 실행한다.
exec DBMS_LOGMNR_D.BUILD('logminer.ora','/home/oracle/logminer');
options=>dbms_logmnr_d.store_in_flat_file--이것의 의미를 모르겠다.
LogMnr Dictionary Procedure started
LogMnr Dictionary File Opened
Procedure executed successfully - LogMnr Dictionary Created
PL/SQL procedure successfully completed.
그럼 생성 되었다는 메세지가 보일것이다.
그 다음으로 분석할 로그파일을 로그파일목록에 등록한다.
목록에서 등록 또는 제거 할 수 있다.
'DBMS_LOGMNR.ADDFILE'으로
나온것 모두 등록해 준다.
exec dbms_logmnr.add_logfile('/u01/app/oracle/oradata/orcl/redo01.log', dbms_logmnr.new);
exec dbms_logmnr.add_logfile('/u01/app/oracle/oradata/orcl/redo02.log', dbms_logmnr.addfile);
exec dbms_logmnr.add_logfile('/u01/app/oracle/oradata/orcl/redo03.log', dbms_logmnr.addfile);
등록된 로그파일은 다음 명령으로 알아 볼 수 있다.
로그파일을 읽어들인다.
dbms_logmnr.start_logmnr 패키지에 의해 리두로그 파일을 분석하고 그 결과를 지정된 경로와
파일에 저장해줌
exec dbms_logmnr.start_logmnr(dictfilename=>'/home/oracle/logminer/logminer01.ora');