Oracle 서버 버전 별 기능비교

- 이 문서는 Oracle 10g, Oracle 11g, Oracle 12c 의 각 버전별 주요 기능에 대한 버전별 제공 여부를 살펴본다.

 

버전 별 기능 비교

- 다음은 주요 기능에 대한 Oralce12c, Oracle11g, Oracle10g 각 버전별 제공 여부를 나타낸다.

 

기능

Oracle 12c

Oracle11g

Oracle10g

 

Multitenant Architecture (Option)

: PDB & CDB

: 여러 개의 DB를 통합하여 하나의 인스턴스로 서비스 가능

Yes

No

No

지정 가능한 복구 시간

Yes

Yes

Yes

블록 레벨 복구

Yes

Yes

Yes

Flashback Query
: undo 이용 과거시점 Data 조회 기능

Yes

Yes

Yes

Flashback Database

:flashback log와 redo를 이용해 Database 전체를 특정시점 이전으로 복구하는 기능

Yes

Yes

Yes

Flashback Table
: undo를 이용 table의 row를 복구

Yes

Yes

Yes

Flashback transaction
:
Commit된 Transaction 복구 기능

Yes

Yes

No

Flashback Data Archive
:데이터 변경 History를 저장할 수 있는 기능(Total Recall option)

Yes

Yes

No

온라인 인덱스
생성 및 재생성

Complete

Complete

Complete

온라인 테이블 재정의

Yes

Yes

Yes

온라인 테이블 Shrink

Yes

Yes

Yes

Log Miner

Yes
DDL지원

Yes
DDL지원

Yes,
DDL지원

자동화된 Standby

Yes

Oracle Data Guard

Yes

Oracle Data Guard

Yes

Oracle Data Guard

손쉬운 Switch-Over

Yes

Yes

Yes

Standby 에서 실시간 질의 기능

Yes
:Active Data Guard

Yes
:Active Data Guard

No

Active Data Guard Fast Sync

: 원거리 SYNC모드의 DR구성가능

Yes

No

No

Standby를 Open하여 사용 후 사용이전의 standby로 원복하는 기능

Yes

Yes

Partial

 








In-Memory Column Store (Option)

: 테이블을 buffer cache와는 별개로 메모리에 columnar format으로 올려 성능향상

Yes

No

No

데이터 분할 기법

Hash cluster, Range, Hash,
Composite, List

Range, Hash,
Composite, List

Range, Hash,
Composite, List

Function or Virtual Column Partitioning:변형된 컬럼값으로 분할 저장 하는 기능

Yes

Yes

No

Interval Partitioning
: Range partition에서 자동화된 partition생성기능

Yes

Yes

No

Global hash Partition Index

Yes

Yes

Yes

Bitmap 인덱스

Yes

Yes

Yes

Function 기반 인덱스

Yes

Yes

Yes

Invisible Indexes
:Index생성 후 기존 application에서 이의 사용은 안되게 하는 기능

Yes

Yes

No

Star 질의

Yes

Yes

Yes

Materialized View

Yes

Yes

Yes

Query Result Cache: Query 결과를 저장해 놓아 재사용할 수 있는 기능

Yes

Yes

No

다양한 분석 함수

Yes

Yes

Yes

Change Data Capture

Yes

Yes

Yes

Down Stream기능 (ETL)

Yes

Yes

Yes

Bitmap 조인 인덱스

Yes

Yes

Yes

Multitable Insert

Yes

Yes

Yes

Upsert(Merge)

Yes

Yes

Yes

Table Functions

Yes

Yes

Yes

Transportable Tablespace

Yes, 확장됨
:이기종간 가능

Yes, 확장됨
:이기종간 가능

Yes, 확장됨
:이기종간 가능

병렬 DML 처리

Yes

Yes

Yes

  병

 

Real Application
Clusters

Real Application
Clusters

Real Application
Clusters

Cache Fusion

Complete

Complete

Complete

투명한 어플리케이션 Failover

Yes

Yes

Yes

어플리케이션 지원

All

All

All

자동 접속 부하 균형

Yes

Yes

Yes

자동화된 DLM 구성

Yes

Yes

Yes

동적 DLM Remastering

Yes

Yes

Yes

Oracle Clusterware (CRS)

Yes

Yes

Yes

ASM (Automatic Storage management)

Yes

Yes

Yes

  관

Heat Map

: 블록단위로 데이터가 사용이 되는지 안되는지 식별가능

Yes

No

No

Automatic Data Optimization

: Heat Map과 ONLINE Move partition기능을 이용하여 미사용파티션데이터를 자동으로 압축, 이동 가능하게 함.

Yes

No

No

자동 통계정보 수집

Yes

Yes

Yes,

과거 통계정보 보관

Yes

Yes

Yes

자동 Undo 관리

Yes

Yes

Yes

자동 데이터 파일 관리

Yes

Yes

Yes

동적 SGA 크기 관리

Yes

Yes

Yes

자동 SQL 실행 메모리 관리

Yes

Yes

Yes

영구적인 초기화 파일

Yes

Yes

Yes

재수행가능한 공간 할당 문장

Yes

Yes

Yes

다중 블록 크기 지원

Yes

Yes

Yes

Real Application Testing(option)

:가동계의 Workload 저장한 후 Test Systems에서 수행(replay)하는 기능

Yes

Yes

No

Data Pump
:고성능의 Export/Import

Yes

Yes

Yes

Cross-Platform Backup & Restore

: 이기종의 플랫폼간 백업 및 리스토어 가능 (using RMAN)

Yes

No

No

Table-Level Recovery From Backups

: RMAN을 통한 테이블 단위로 복구 가능

Yes

No

No

Java 기반의 시스템 도구

Yes

Yes

Yes

Oracle Scheduler

Yes

Yes

Yes

SQL Access Advisor

Yes

Yes

Yes

SQL Tuning Advisor

Yes

Yes

Yes

EM Control 및 EM Grid Control을 통한 시스템 통합관리

Yes

Yes

Yes

성능정보 수집기능(Automatic Workload Repository)

Yes

Yes

Yes

ADDM (자동 Database진단 monitor)

Yes

Yes

Yes

  보

강력한 데이터 보안 기능

Yes

Yes

Yes

3-Tier 보안 기능

Yes

Yes

Yes

Fine-Grained Auditing

Yes

Yes

Yes

Oracle Label Security

Yes

Yes

Yes

실시간 데이터 Masking

: Real-time sensitive data redaction 기능

Yes

Yes

: 11.2.0.4 이후 가능

No

표준 기반 PKI

Yes

Yes

Yes

컬럼 레벨 데이터 암호화

Yes

Yes

Yes

Tablespace 레벨 데이터 암호화

Yes

Yes

No

Directory 서비스

Yes

Yes

Yes

Enterprise User 및 Role 관리

Yes

Yes

Yes

SSL 지원

Yes

Yes

Yes

RADIUS Adapter 지원

Yes

Yes

Yes

KERBEROS 보안 모델 지원

Yes

Yes

Yes

LDAP 통합

Yes

Yes

Yes

VPD (Virtual Private Database)

Yes

Yes

Yes

Encrypted LOBs

Yes

Yes

No

  개

Partial Indexes for Partitioned Tables

: 파티션 테이블의 일부 파티션만에 local or global index를 생성가능.

Yes

No

No

ONLINE Move Partition

: 파티션 이동 온라인으로 가능

Yes

No

No

데이터베이스 내의
XML Type 지원

Yes

Yes

Yes

XML Developer's Kit

Yes

Yes

Yes

객체 관계형 모델

Yes, Complete

Yes, Complete

Yes, Complete

ANSI/ISO SQL 1999 지원

Yes

Yes

Yes

C++ Call Interface

Yes

Yes

Yes

Scrolling Cursors

Yes

Yes

Yes

Bulk Binding

Yes

Yes

Yes

PL/SQL Native 컴파일

Yes

Yes

Yes

통합된 JVM

Yes

Yes

Yes

SQLJ

Yes

Yes

Yes

Java Stored Procedures

Yes

Yes

Yes

JDBC 2.0 지원

Yes

Yes

Yes

Java Native 컴파일

Yes

Yes

Yes

JSON data type 지원

: JavaScript Object Notation

Yes

No

No

UltraSearch

Yes

Yes

Yes

Native PL/SQL지원

Yes

Yes

Yes

ODP.Net (.Net 지원)

Yes

Yes

Yes

 


< 참고 > Oracle 12c New Feature 주요기능 요약

아키텍처

1

Multitenant Architecture

여러 개의 DB 통합하여 하나의 인스턴스로 서비스 가능. 여러 DB통합하여 자원을 효율적으로 이용가능. 손쉬운 DB이전 통합, DB 자원할당 가능

2

In-Memory Column Store

테이블을 buffer cache와는 별개로 메모리에 columnar format으로 올려 성능향상. 특히 OLAP 쿼리 수행시 월등한 성능 보장

파티션

3

Partial Indexes for Partitioned Tables

파티션 테이블의 일부 파티션만에 local or global index 생성가능. 대량의 데이터가 Insert되는 파티션에 대한 Index 생성하지 않도록 하여 성능향상

4

Asynchronous global index maintenance for DROP and TRUNCATE

특정 파티션이 Drop/Truncate 되더라도 Global Index unusable 빠지지 않고 유지됨

5

ONLINE Move Partition

파티션 이동 온라인으로 가능

데이터관리

6

Advanced index compression

인덱스 압축 기능 향상

7

Heat Map

블록단위로 데이터가 사용이 되는지 안되는지 식별가능

8

Automatic Data Optimization

Heat Map ONLINE Move partition기능을 이용하여 미사용파티션데이터를 자동으로 압축, 이동 가능하게 . DBMS내의 ILM구현

ADG

9

Active Data Guard Fast Sync

ADG DR구축시 LOG정보가 STANDBY MEMORY에만 전달되면 ACK받음.(ADG SYNC모드 성능향상)

10

Active Data Guard Far Sync

중계서버를 두어 원거리(대륙간) SYNC모드의 DR구성가능

RMAN

11

Cross-Platform Backup & Restore

이기종의 플랫폼간 백업 리스토어 가능. DB migration 단순화

12

Table-Level Recovery From Backups

RMAN으로 백업본에서 테이블 단위로 복구 가능

 

[참고 문서 사이트]

  - Oracle Database New Features Guide documentation

  - http://docs.oracle.com/database/121/NEWFT/toc.htm


블로그 이미지

운명을바꾸는자

IT와 함께 살아가는 삶

,

AWR Report 기초

1. IT Story/DB 2015. 8. 4. 21:30

   

   

1. AWR 이란?

1. AWR 이란?

AWR(Automatic Workload Repository)은 모든 주요 통계와 작업 로드에 대한 정보 스냅샷 형태로 저장하는 저장소이다.

AWR 스냅샷은 기본적으로 시간당 1회 캡처되며 8일간(Oracle Database 11g) 데이터베이스에 보존되며 수집 및

보관주기의 변경이 가능하다.

사용자는 이를 이용하여 성능 문제 분석 및 운영 예측 작업을 수행할 수 있으며 AWR에 의해 수집되는 데이터는 다음과 같다.

수집 데이터

분석 내용

DB 대기 이벤트 및 통계 정보

오라클 자원(경합현상, 메모리, 세그먼트, 락, RAC등) 사용 현황 파악

시스템 통계 정보

CPU, 디스크, 네트워크 등 시스템 자원 이용 통계

데이터베이스 부하 정보

그룹화된 DB 사용 부하의 통계 수치

SQL 수행 정보

SQL 통계 정보 및 실행 계획 정보

활동 세션 정보

ASH(Active Session Hisory)를 이용한 해당 스냅샷 시점의 세션 정보 파악 가능

   

2. AWR 관리

1. AWR 스냅샷 관리 방법

AWR 스냅샷이란 메모리에서 디스크로 저장하는 시점의 AWR 데이터를 의미한다. 스냅샷에서도 저장 공간

크기, 저장 기간, 수집 주기 등을 고려해야 하며 백업 및 복구 등의 관리가 필요하다. 오라클에서는 AWR 스냅샷

관리를 위해 DBMS_WORKLOAD_REPOSITORY 패키지를 제공한다.

항목

사용법

AWR 스냅샷 삭제

BEGIN

DBMS_WORKLOAD_REPOSITORY.DROP_SNAPSHO_RANGE

(LOW_SNAP_ID => snap_id, HIGH_SNAP_ID => snapid [DBID => dbid]);

END;

/

AWR 스냅샷 설정 변경

BEGIN

DBMS_WORKLOAD_REPOSITORY.MODIFY_SNAPSHOT_SETTINGS

([RETENTION => retention_time][,INTERVAL => interval_time]

[,TOPNSQL => topn_sql_number]);

END;

/

베이스라인 설정

BEGIN

DBMS_WORKLOAD_REPOSITORY.CREATE_BASELINE

(START_SNAP_ID => sanp_id, END_SNAPID => sanp_id,

BASELINE_NAME => 'baseline_name'[, DBID => dbid]);

END;

/

베이스라인 삭제

BEGIN

DBMS_WORKLOAD_REPOSITORY.DROP_BASELINE

(BASELINE_NAME => 'baseline_name'[, CASCADE => true|false][,DBID => dbid]);

END;

/

   

2. AWR 데이터 백업 복구

AWR 관리 주기 및 테이블스페이스 공간 부족 등으로 AWR 데이터를 삭제할 경우, 삭제 대상 AWR 데이터를 백업할

필요가 발생할 수 있다. 이때, awrextr.sql 스크립트를 수행하면 데이터 펌프를 이용하여 AWR 데이터를 덤프 파일로

저장 할 수 있으며 추후 이 파일을 이용하여 복구를 수행할 수 있다.

 

1. AWR 데이터 백업

- awrextr.sql를 수행하여 백업 진행 ($ORACLE_HOME/rdbms/admin에 존재)

- 지정한 file name의 ".dmp"로 파일 생성

2. AWR 데이터 복구

- awrload.sql을 수행하여 복구 진행 ($ORACLE_HOME/rdbms/admin에 존재)

- 백업된 AWR 데이터가 저장되어 있던 데이터베이스 ID와 동일한 데이터베이스 ID를 갖는 데이터 베이스에

적재할 수 없음.


3. AWR 보고서 생성

AWR 보고서는 시작 스냅샷 번호와 종료 스냅샷 번호를 설정하여, 두 구간의 대기 이벤트 발생 횟수 및 통계치의

차이를 계산하여 보여준다. 주의할 점은 인스턴스가 종료할 때마다 대기 이벤트 및 통계수치가 재설정되므로,

스냅샷 구간 사이에 인스턴스가 종료된 적이 있다면 AWR 보고서의 수치는 의미가 없으며, 생성되지 않는다.

AWR 보고서는 DBMS_WORKLOAD_REPOSITORY 패키지와 오라클에서 제공하는 스크립트를 사용하여 생성 할 수 있다.

모든 AWR 관련 스크립트는 다음 위치에 있다.

  • $ORACLE_HOME/rdbms/admin/
  • 사용 용도별 스크립트

사용 용도

스크립트

AWR DB 보고서 생성

awrrpt.sql, awrrpti.sql

AWR DB 비교 보고서 생성

awrddrpt.sql, awrddrpi.sql

AWR SQL 보고서 생성

awrsqrpt.sql, awrsqrpi.sql

AWR 정보 검색 보고서

awrinfo.sql

ASH 보고서 생성

ashrpt.sql, ashrpti.sql

ADDM 보고서 생성

addmrpt.sql, addmrpti.sql

기타 스크립트

awrddinp.sql, awrinput.sql, awrinpnmp.sql


1. AWR 보고서 생성

AWR 보고서를 생성하기 위해서는 다음과 같은 권한이 필요하다.

  • SELECT ANY DIRECTORY 권한
  • SYS.DMBS_WORKLOAD_REPOSITORY 패키지 실행 권한

  AWR 보고서를 생성하기 위해서는 awrrpt.sql과 awrpti.sql 스크립트를 사용한다.

스크립트

설명

awrrpt.sql

스크립트를 수행한 인스턴스의 AWR 보고서를 생성한다.

awrrpti.sql

DB ID와 인스턴스 번호를 지정해서 AWR 보고서를 생성한다.

   

1) awrrpt.sql을 이용한 AWR 보고서 생성 단계

 

awrrpt.sql 실행

 

AWR 보고서 출력 타입 지정 ( HTML / TEXT ) : HTML타입으로 지정

 

awrrpt.sql을 수행하는 DB ID가 자동으로 선택 됐으며 스냅샷 ID 리스트를 보여주는 기간을 지정한다.

   

스냅샷 번호 목록이 보이면 AWR 보고서를 생성하려는 구간의 시작 스냅샷 번호와 종료 스냅샷 번호를 지정한다.

생성될 AWR 보고서 이름을 지정한다. awr_test.html로 지정

   

 

2) DBMS_WORKLOAD_REPOSITORY 패키지를 사용한 방법

프로시저

설명

AWR_REPORT_TEXT

텍스트 형식의 AWR 보고서 생성

AWR_REPORT_HTML

웹 문서 형식의 AWR 보고서 생성

 

AWR_REPORT_HTML 사용법

SELECT OUTPUT

FROM TABLE (DBMS_WORKLOAD_REPOSITOR.AWR_REPORT_HTML(

:DBID, :INST_ID, :BEGIN_SNAP, :END_SNAP) );


블로그 이미지

운명을바꾸는자

IT와 함께 살아가는 삶

,


Oracle Database Applicance(ODA X5-2)

   

1.ODA 장비 전면 부 모습

   

2. ODA 장비 후면 부 모습

   

3. ODA 세부 규격

   

4. ODA 환경 확인 Command

oakcli show asr

Displays the Oracle Auto Service Request configuration

oakcli show cooling

Displays the status of the cooling units

oakcli show controller

Displays information about the disk controllers

oakcli show core_config_key

Displays information a bout the core deploy ment

oakcli show cpupool

Displays information about mappings between cores and virtual machines

oakcli show databases

Displays information about the databases

oakcli show dbhomes

Displays information about the database homes

oakcli show db_config_params

Displays configuration file names and parameters

oakcli show disk

Displays information about shared or local disks

oakcli show diskgroup

Displays information about Oracle ASM disk groups.

oakcli show env_hw

Displays the current server's environment type and hardware version

oakcli show expander

Displays information about the expanders

oakcli show enclosure

Displays information about the storage enclosure

oakcli show memory

Displays information about the memory subsystem

oakcli show network on

Displays information about the network subsystem

oakcli show power on p

Displays the status of the power supply subsystem

oakcli show processor

Displays processor (CPU) information

oakcli show repo on pa

Displays information about virtual machine repositories

oakcli show server on

Displays information about the server subsystem

oakcli show storage

Displays in formation about the storage

oakcli show validation storage

Displays status (enabled or disabled) of validation storage error reporting

oakcli show validation storag

eerrors Displays hard storage errors

oakcli show validation storage

failures Displays soft storage errors

oakcli show version

Displays version information for the software and firmware

oakcli show vlan

Displays version information about virtual local area networks

oakcli show vm

Displays version information about virtual machines

oakcli show vmtemplate

Displays information about virtual machine templates

   

   

   


블로그 이미지

운명을바꾸는자

IT와 함께 살아가는 삶

,


Function 수행횟수 확인 TEST

   

1.TEST Function 생성

create or replace function

Scott.F1(p_num IN number) return number is v_num number;

begin

select max(e.empno)

into v_num

from emp E

where e.deptno = p_num;

return v_num;

end;

/

    

2.원본 SQL문 Trace 수행

- 원본 Trace 아래에 Funtion 내부적으로 수행된 SQL문에 대하여 Trace가 남는다.

   

select D.DEPTNO,scott.F1(D.DEPTNO) f_deptno

from scott.DEPT D

   

 

********************************************************************************

   

  • Funtion 내부 쿼리 내역

   

SQL ID: dxa9c0qzbrxrt Plan Hash: 2083865914

   

SELECT SUM(E.EMPNO)

FROM

EMP E WHERE E.DEPTNO = :B1

 

 

   

  • Function 내부의 Sum하는 SQL문이 바인드변수(:B1)을 바꾸어 가면서 4회 반복하여 Function을 호출한다.
  • Function Call의 호출 수를 최소화하거나 Function 내부의 SQL문을 개선하는 것을 생각해 볼 수 있다.


블로그 이미지

운명을바꾸는자

IT와 함께 살아가는 삶

,



1. Decode Function TEST

  • Decode Funtion에 대하여 TEST를 진행

   

1-1) 개선 전

Compile Time : 2013/07/12 13:22:54

Trace File : C:\oracle\product\10.2.0\admin\Gbpr_tes\udump\gbpr_ora_4752.trc

Trace Version : 10.2.0.4.0

********************************************************************************

   

select empno, sal1,sal2,sal3

from (

select empno,

sum(sal) as sal1,

0 as sal2,

0 as sal3

from scott.emp_TEST a

where a.empno='7844'

group by empno

union all

select empno,

0 as sal1,

sum(sal) as sal2,

0 as sal3

from scott.emp_TEST b

where b.empno='7900'

group by empno

union all

select empno,

0 as sal1,

0 as sal2,

sum(sal) as sal3

from scott.emp_TEST b

where b.empno='7782'

group by empno

)

order by EMPNO

 

  

********************************************************************************

   

1-2) 개선 후

Compile Time : 2013/07/12 13:23:30

Trace File : C:\oracle\product\10.2.0\admin\Gbpr_tes\udump\gbpr_ora_4752.trc

Trace Version : 10.2.0.4.0

********************************************************************************

   

select empno,

NVL(sum(decode(empno,'7844', sal)),0) as sal1,

NVL(sum(decode(empno,'7900',sal)),0) as sal2,

NVL(sum(decode(empno,'7782',sal)),0) as sal3

from scott.emp_TEST a

where a.empno in ('7844','7900','7782')

group by empno

order by EMPNO

   

********************************************************************************

  

블로그 이미지

운명을바꾸는자

IT와 함께 살아가는 삶

,


 

1. Clone database 생성

 

1) Source Database 사전 작업

1-1) Backup Database

Source Database Rman 접속

   

$ rman target /

   

Controlfile Auto backup 이 활성화 되어있지 않은 경우 활성화 시켜준다.

   

RMAN> configure controlfile autobackup on;

   

RMAN> configure controlfile autobackup format for device type disk to '/u01/app/oracle/rman_bak/%F';

   

Database backup

   

RMAN> RUN

2> {

3> allocate channel ch1 type disk

4> format '/u01/app/oracle/rman_bak/%d_DB_%u_%s_%p';

5> backup database plus archivelog;

6> release channel ch1;

7> }

    

1-2) Prameter File 백업

Controlfile Auto backup 시에 자동으로 Parameter file 도 백업이 되지만

Pfile 로 생성해서 직접 수정하기 위해 따로 한번 더 생성해준다.

   

SQL> create pfile ='/home/oracle/initTEST.ora' from spfile;

   

RMAN> RESTORE SPFILE TO '/tmp/spfileTEMP.ora' FROM AUTOBACKUP;

   

1-3) Backup File 전송

Source 에서 Target 으로 SCP 를 이용해 RMAN Backup 파일들과 parameter file 전송

   

$ scp FILENAME oracle@192.168.1.100:/home/oracle/rman_bak/

   

2. Clone DB 설정(Target)

2-1) Parameter File 설정

기존 RAC 관련 파라미터는 삭제하거나 주석처리하고, 경로나 메모리부분을 환경에 맞게 조절

DB NAME 의 경우 추후 변경

$ vi initTEST.ora

   

*.audit_file_dest='/app/oracle/admin/TEST/adump'

*.audit_sys_operations=TRUE

*.audit_trail='db'

#*.cluster_database=true

*.compatible='11.2.0.2.0'

*.db_create_file_dest='/app/oracle/oradata/TEST'

*.db_files=1024

*.db_name='TESTORA'

*.db_recovery_file_dest='/app/oracle/flash_recovery_area'

*.db_recovery_file_dest_size=4992899480

*.diagnostic_dest='/app/oracle'

*.dispatchers='(PROTOCOL=TCP) (SERVICE=TESTXDB)'

*.fast_start_mttr_target=300

*.global_names=TRUE

#TESTORA2.instance_number=2

#TESTORA1.instance_number=1

*.log_archive_format='%t_%s_%r.dbf'

*.open_cursors=1000

*.os_authent_prefix=''

*.pga_aggregate_target=15899340

*.processes=800

#*.remote_listener='etk-scan:1521'

*.remote_login_passwordfile='exclusive'

*.session_cached_cursors=100

*.sga_target=1001798690

#TESTORA2.thread=2

#TESTORA1.thread=1

TEST.undo_tablespace='UNDOTBS1'

#TSETORA2.undo_tablespace='UNDOTBS2'

#*.use_large_pages='ONLY'

   

2-2) Password File 생성/ Startup nomount

   

$ orapwd file=orapwTEST entries=6 password=oracle

   

nomount 상태로 startup

   

SQL> startup nomount

   

2-3) Controlfile restore / Backuppiece 등록

Source DB 의 Database backup 시에 autobackup 으로 받아진 file 로 Restore

   

RMAN> restore controlfile from '/u01/11g_db/rman_db_backups/con_c-208065887-20121014-01';

   

Restore 시에 기존에 받았던 백업들이 RMAN 에 등록이 되나 실제로 존재하지 않기 때문에 삭제해주고 새로 등록해준다.

   

RMAN> crosscheck backup;

RMAN> list expired backup;

RMAN> delete expired backup;

   

RMAN> catalog backuppiece '/home/oracle/rman_bak/TESTORA_DB_0uq6bchc_30_1';

RMAN> catalog backuppiece '/home/oracle/rman_bak/TESTORA_DB_0vq6bcid_31_1;

RMAN> catalog backuppiece '/home/oracle/rman_bak/ TESTORA_DB_0sq6bce7_28_1;

RMAN> catalog backuppiece '/home/oracle/rman_bak/TESTORA_DB_0tq6bcfu_29_1;

 

2-4) Restore Datafile

Controlfile 이 Restore 되었기 때문에 mount 시킨 뒤

Datafile Restore 진행

   

SQL> alter database mount;

   

RMAN> run {

2> set until sequence 63 thread 2; --set until cancel;

3> set newname for datafile 1 to '/backup/oradata/system01.dbf';

4> set newname for datafile 2 to '/backup/oradata/sysaux01.dbf';

5> set newname for datafile 3 to '/backup/oradata/undotbs01.dbf';

6> set newname for datafile 4 to '/backup/oradata/undotbs02.dbf';

7> set newname for datafile 5 to '/backup/oradata/users01.dbf';

8> restore datafile 1;

9> restore datafile 2;

10> restore datafile 3;

11> restore datafile 4;

12> restore datafile 5;

13> switch datafile all;

14> recover database;

15> }

   

2-5) RedoLog File 이름 수정 / Database Open

기존 ASM 기반의 경로와 이름으로 되어있는 것을 현재 경로에 맞게 수정해준다.

   

SQL> select member from v$logfile;

MEMBER

--------------------------------------------------------------------------------

+REDO/etk/onlinelog/group_1.256.860865469

+REDO/testora/onlinelog/group_2.257.860865477

+REDO/testora/onlinelog/group_3.258.860865841

+REDO/testora/onlinelog/group_4.259.860865849

   

SQL> alter database rename file '+REDO/testora/onlinelog/group_1.256.860865469' to

2 '/app/oracle/oradata/TEST/redo01.log';

SQL> alter database rename file '+REDO/testora/onlinelog/group_3.258.860865841' to

2 '/app/oracle/oradata/TEST/redo03.log';

SQL> alter database rename file '+REDO/testora/onlinelog/group_4.259.860865849' to

2 '/app/oracle/oradata/TEST/redo04.log';

SQL> alter database rename file '+REDO/testora/onlinelog/group_4.259.860865849' to

2 '/app/oracle/oradata/TEST/redo04.log';

   

수정 완료 후 Database open

   

SQL > alter database open resetlogs;

    

2-6) 필요 없는 Redo Log group 삭제

RAC 에서 사용하던 THREAD 2 번의 Redo Log Goup 을 삭제

   

SQL> select thread#, status, enabled from v$thread;

THREAD# STATUS ENABLED

---------- ------ --------

1 OPEN PUBLIC

2 CLOSED PUBLIC

   

SQL> select group# from v$log where thread#2;

GROUP#

----------

3

4

   

SQL> alter database disable thread 2;

SQL> alter database drop logfile group 3;

SQL> alter database drop logfile group 4;

   

   

2-7) DB_NAME 변경

DB NAME 을 변경할 필요가 있을 경우 nid utility 를 사용해서 변경해준다

   

SQL> shutdown immediate

SQL> startup mount

   

$ nid target=sys/oracle dbname=TEST


블로그 이미지

운명을바꾸는자

IT와 함께 살아가는 삶

,


1.Data Masking 옵션(무작위 자리수)

   

   

2.해당 Table 컬럼:EMAIL - Unique Index

3.Data Masking 옵션- 무작위 자릿수

 

   

4.변경된 데이터 값 확인

   

5.상태확인

  • 기존에 가지고 있는 Trigger 및 Index 그리고 Constraints가 정상적으로 존재하는 것을 확인할 수 있습니다.
  • Check sum으로 인하여 Data Masking 후 Unique Index 생성시 해당 열에 대한 중복값이 발생하지 않아 에러 없이 잘 적용이 되는 것을 확인할 수 있습니다.

       

   

   

   

   

<file_error msg="지정된 경로를 찾을 수 없습니다." n="3"/>

-- ¿¿ ¿¿¿¿¿¿: test

-- ¿¿¿¿ ¿¿ ¿¿: 03-9¿ -2012 18:42

¿¿¿ ¿¿¿ ¿¿ ¿

User is "SYS"

COMMIT

ALTER SESSION ENABLE PARALLEL DML

DROP TABLE "MGMT_DM_TT_48" PURGE

¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿¿, ¿¿ ¿¿ ¿

declare

adj number:=0;

num number:=0;

begin

select length(count(*)) into adj from (select distinct "EMAIL" from "HR"."EMPLOYEES");

num := adj;

adj := greatest(adj - 3, 0);

execute immediate 'create table MGMT_DM_TT_48

(orig

_val null, new_val null) NOLOGGING PARALLEL as

select CAST(null AS VARCHAR2(25)) orig_val, CAST(null AS VARCHAR2(25)) new_val from dual union all

select s.orig_val,

case

when s.subset = 1 then

CAST(

lpad(trunc(dbms_

random.value(0, power(10, 2 - least(2, greatest('||adj||' - 0, 0))) - 1)), 2 - least(2, greatest('||adj||' - 0, 0)), 0)

|| lpad(nvl(substr(s.new_num, 1, 3 + least(2, greatest('||adj||' - 0, 0))),0),3 + least(2, greatest('||adj||' - 0, 0)), 0)

 

AS VARCHAR2(25))

end new_val

from (select rownum rn, orig_val, subset, rid, lpad(rownum - 1, '||num||', 0) new_num

from (select "EMAIL" orig_val, min(rowid) rid, min(

case

when 1=1 then 1

end

)

subset

from "HR"."EMPLOYEES" group by "EMAIL")) s

where 1=1 and s.orig_val is not null

';

DBMS_STATS.GATHER_TABLE_STATS(NULL, '"MGMT_DM_TT_48"', estimate_percent=>DBMS_STATS.AUTO_SAMPLE_SIZE, degree=>DBMS_STATS.DEFAULT_DEGREE);

end;

DROP TRIGGER "HR"."SECURE_EMPLOYEES"

DROP TRIGGER "HR"."UPDATE_JOB_HISTORY"

DECLARE

CURSOR fk_sql IS select refr.owner, refr.table_name, refr.constraint_name

from dba_constraints refd, dba_constraints refr

where refd.owner = 'HR' and

refd.table_name = 'EMPLOYEES' and

refr.constraint_ty

pe = 'R' and

refr.r_owner = refd.owner and

refr.r_constraint_name = refd.constraint_name;

BEGIN

FOR fk IN fk_sql

LOOP

EXECUTE IMMEDIATE 'ALTER TABLE "' || fk.owner || '"."' ||

fk.table_name || '" DROP CONSTRAINT "

' || fk.constraint_name || '"';

END LOOP;

END;

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿ ¿:

CREATE OR REPLACE procedure "HR".MGMT$MASK_GRANT_47 AS

grant_cur INTEGER;

BEGIN

grant_cur := DBMS_SQL.OPEN_CURSOR;

DBMS_SQL.PARSE (grant_cur, ' REVOKE REFERENCES ON "HR"."EMPLOYEES" F

ROM "OE"', DBMS_SQL.NATIVE);

DBMS_SQL.CLOSE_CURSOR (grant_cur);

END;

BEGIN "HR".MGMT$MASK_GRANT_47; END;

DROP procedure "HR".MGMT$MASK_GRANT_47

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿ ¿:

CREATE OR REPLACE procedure "HR".MGMT$MASK_GRANT_47 AS

grant_cur INTEGER;

BEGIN

grant_cur := DBMS_SQL.OPEN_CURSOR;

DBMS_SQL.PARSE (grant_cur, ' REVOKE SELECT ON "HR"."EMPLOYEES" FROM

"OE"', DBMS_SQL.NATIVE);

DBMS_SQL.CLOSE_CURSOR (grant_cur);

END;

BEGIN "HR".MGMT$MASK_GRANT_47; END;

DROP procedure "HR".MGMT$MASK_GRANT_47

DECLARE

CURSOR c_sql IS select owner, table_name, constraint_name,

constraint_type, generated, index_name from dba_constraints

where owner = 'HR' and

table_name = 'EMPLOYEES' and

constraint_type <> 'R';

BEGIN

FOR c I

N c_sql

LOOP

EXECUTE IMMEDIATE 'ALTER TABLE "' || c.owner || '"."' ||

c.table_name || '" DROP CONSTRAINT "' || c.constraint_name || '"';

END LOOP;

END;

DROP INDEX "HR"."EMP_DEPARTMENT_IX"

DROP INDEX "HR"."EMP_EMAIL_UK"

DROP INDEX "HR"."EMP_EMP_ID_PK"

DROP INDEX "HR"."EMP_JOB_IX"

DROP INDEX "HR"."EMP_MANAGER_IX"

DROP INDEX "HR"."EMP_NAME_IX"

ALTER TABLE "HR"."EMPLOYEES" RENAME TO "EMPLOYEES$DMASK"

CREATE TABLE "HR"."EMPLOYEES" TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 1 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING NOCOMPRESS PARALLEL AS SELECT s."EMPLOYEE_ID", s."FIRST_NAME", s."LAST_NAME", c0m48.NEW_VAL "EMAIL", s."PHONE_

NUMBER", s."HIRE_DATE", s."JOB_ID", s."SALARY", s."COMMISSION_PCT", s."MANAGER_ID", s."DEPARTMENT_ID" FROM "HR"."EMPLOYEES$DMASK" s , MGMT_DM_TT_48 c0m48 WHERE sys_op_map_nonnull(s."EMAIL") = sys_op_map_nonnull(c0m48.ORIG_VAL)

ALTER TABLE "HR"."EMPLOYEES" NOPARALLEL

DROP TABLE "HR"."EMPLOYEES$DMASK" PURGE

CREATE INDEX "HR"."EMP_DEPARTMENT_IX" ON "HR"."EMPLOYEES" ("DEPARTMENT_ID") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

CREATE UNIQUE INDEX "HR"."EMP_EMAIL_UK" ON "HR"."EMPLOYEES" ("EMAIL") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

CREATE UNIQUE INDEX "HR"."EMP_EMP_ID_PK" ON "HR"."EMPLOYEES" ("EMPLOYEE_ID") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

CREATE INDEX "HR"."EMP_JOB_IX" ON "HR"."EMPLOYEES" ("JOB_ID") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

CREATE INDEX "HR"."EMP_MANAGER_IX" ON "HR"."EMPLOYEES" ("MANAGER_ID") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

CREATE INDEX "HR"."EMP_NAME_IX" ON "HR"."EMPLOYEES" ("LAST_NAME", "FIRST_NAME") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

ALTER TABLE "HR"."EMPLOYEES" MODIFY ("EMAIL" CONSTRAINT "EMP_EMAIL_NN" NOT NULL )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_EMAIL_UK" UNIQUE ("EMAIL") )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_EMP_ID_PK" PRIMARY KEY ("EMPLOYEE_ID") )

ALTER TABLE "HR"."EMPLOYEES" MODIFY ("HIRE_DATE" CONSTRAINT "EMP_HIRE_DATE_NN" NOT NULL )

ALTER TABLE "HR"."EMPLOYEES" MODIFY ("JOB_ID" CONSTRAINT "EMP_JOB_NN" NOT NULL )

ALTER TABLE "HR"."EMPLOYEES" MODIFY ("LAST_NAME" CONSTRAINT "EMP_LAST_NAME_NN" NOT NULL )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_SALARY_MIN" CHECK (salary > 0) )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_MANAGER_FK" FOREIGN KEY ("MANAGER_ID") REFERENCES "HR"."EMPLOYEES" ("EMPLOYEE_ID") )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_DEPT_FK" FOREIGN KEY ("DEPARTMENT_ID") REFERENCES "HR"."DEPARTMENTS" ("DEPARTMENT_ID") )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_JOB_FK" FOREIGN KEY ("JOB_ID") REFERENCES "HR"."JOBS" ("JOB_ID") )

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿ ¿:

CREATE OR REPLACE procedure "HR".MGMT$MASK_GRANT_47 AS

grant_cur INTEGER;

BEGIN

grant_cur := DBMS_SQL.OPEN_CURSOR;

DBMS_SQL.PARSE (grant_cur, ' GRANT REFERENCES ON "HR"."EMPLOYEES" TO

"OE"', DBMS_SQL.NATIVE);

DBMS_SQL.CLOSE_CURSOR (grant_cur);

END;

BEGIN "HR".MGMT$MASK_GRANT_47; END;

DROP procedure "HR".MGMT$MASK_GRANT_47

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿ ¿:

CREATE OR REPLACE procedure "HR".MGMT$MASK_GRANT_47 AS

grant_cur INTEGER;

BEGIN

grant_cur := DBMS_SQL.OPEN_CURSOR;

DBMS_SQL.PARSE (grant_cur, ' GRANT SELECT ON "HR"."EMPLOYEES" TO "OE

"', DBMS_SQL.NATIVE);

DBMS_SQL.CLOSE_CURSOR (grant_cur);

END;

BEGIN "HR".MGMT$MASK_GRANT_47; END;

DROP procedure "HR".MGMT$MASK_GRANT_47

CREATE OR REPLACE TRIGGER "HR"."SECURE_EMPLOYEES" BEFORE

INSERT

OR UPDATE

OR DELETE ON "HR"."EMPLOYEES" BEGIN

secure_dml;

END secure_employees;

ALTER TRIGGER "HR"."SECURE_EMPLOYEES" DISABLE

CREATE OR REPLACE TRIGGER "HR"."UPDATE_JOB_HISTORY" AFTER

UPDATE OF "DEPARTMENT_ID", "JOB_ID" ON "HR"."EMPLOYEES" REFERENCING OLD AS OLD NEW AS NEW FOR EACH ROW BEGIN

add_job_history(:old.employee_id, :old.hire_date, sysdate,

:old.job_

id, :old.department_id);

END;

COMMENT ON COLUMN "HR"."EMPLOYEES"."COMMISSION_PCT" IS 'Commission percentage of the employee; Only employees in sales

department elgible for commission percentage'

COMMENT ON COLUMN "HR"."EMPLOYEES"."DEPARTMENT_ID" IS 'Department id where employee works; foreign key to department_id

column of the departments table'

COMMENT ON COLUMN "HR"."EMPLOYEES"."EMAIL" IS 'Email id of the employee'

COMMENT ON COLUMN "HR"."EMPLOYEES"."EMPLOYEE_ID" IS 'Primary key of employees table.'

COMMENT ON COLUMN "HR"."EMPLOYEES"."FIRST_NAME" IS 'First name of the employee. A not null column.'

COMMENT ON COLUMN "HR"."EMPLOYEES"."HIRE_DATE" IS 'Date when the employee started on this job. A not null column.'

COMMENT ON COLUMN "HR"."EMPLOYEES"."JOB_ID" IS 'Current job of the employee; foreign key to job_id column of the

jobs table. A not null column.'

COMMENT ON COLUMN "HR"."EMPLOYEES"."LAST_NAME" IS 'Last name of the employee. A not null column.'

COMMENT ON COLUMN "HR"."EMPLOYEES"."MANAGER_ID" IS 'Manager id of the employee; has same domain as manager_id in

departments table. Foreign key to employee_id column of employees table.

(useful for reflexive joins and CONNECT BY query)'

COMMENT ON COLUMN "HR"."EMPLOYEES"."PHONE_NUMBER" IS 'Phone number of the employee; includes country code and area code'

COMMENT ON COLUMN "HR"."EMPLOYEES"."SALARY" IS 'Monthly salary of the employee. Must be greater

than zero (enforced by constraint emp_salary_min)'

COMMENT ON TABLE "HR"."EMPLOYEES" IS 'employees table. Contains 107 rows. References with departments,

jobs, job_history tables. Contains a self reference.'

BEGIN DBMS_STATS.GATHER_TABLE_STATS('"HR"', '"EMPLOYEES"', estimate_percent=>DBMS_STATS.AUTO_SAMPLE_SIZE, degree=>DBMS_STATS.DEFAULT_DEGREE, cascade=>TRUE); END;

¿¿¿ ¿¿¿¿ ¿¿¿¿¿¿¿. ¿¿ ¿¿¿ ¿¿¿¿¿.

¿¿ ¿¿¿ ¿¿¿ ¿¿ ¿

¿¿ ¿¿¿ ¿¿¿¿ ¿¿¿

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿

¿¿¿ ¿¿¿¿ ¿¿¿¿ ¿¿¿

¿¿¿¿ ¿¿ ¿¿

SQL> set ver on

 

블로그 이미지

운명을바꾸는자

IT와 함께 살아가는 삶

,

 

0.HR User 현재상태

   

   

EMP_DEPT_FK        Referential Integrity        Enabled        No Action        Not Deferrable        Immediate        Validated                        1        DEPARTMENT_ID

EMP_EMAIL_NN        Check        Enabled                Not Deferrable        Immediate        Validated                        1        "EMAIL" IS NOT NULL

EMP_EMAIL_UK        Unique Key        Enabled                Not Deferrable        Immediate        Validated                        1        EMAIL

EMP_EMP_ID_PK        Primary Key        Enabled                Not Deferrable        Immediate        Validated                        1        EMPLOYEE_ID

EMP_HIRE_DATE_NN        Check        Enabled                Not Deferrable        Immediate        Validated                        1        "HIRE_DATE" IS NOT NULL

EMP_JOB_FK        Referential Integrity        Enabled        No Action        Not Deferrable        Immediate        Validated                        1        JOB_ID

EMP_JOB_NN        Check        Enabled                Not Deferrable        Immediate        Validated                        1        "JOB_ID" IS NOT NULL

EMP_LAST_NAME_NN        Check        Enabled                Not Deferrable        Immediate        Validated                        1        "LAST_NAME" IS NOT NULL

EMP_MANAGER_FK        Referential Integrity        Enabled        No Action        Not Deferrable        Immediate        Validated                        1        MANAGER_ID

EMP_SALARY_MIN        Check        Enabled                Not Deferrable        Immediate        Validated                        1        salary > 0

   

   

1.인덱스 없는 컬럼

   

  • 선택한 컬럼명(phone_number) : 해당 컬럼에는 인덱스가 없다.

       

  • 현재 데이터상태

   

   

  • Masking 조건(무작위 숫자 삽입)

       

   

  • 변경된 데이터 현태

       

   

  • 상태확인
  • Constraints/Index 에 아무 이상이 없다.

       

   

   

<전체 실행된 스크립트 내역>

-- ¿¿ ¿¿¿¿¿¿: test

-- ¿¿¿¿ ¿¿ ¿¿: 03-9¿ -2012 13:22

¿¿¿ ¿¿¿ ¿¿ ¿

User is "SYS"

COMMIT

ALTER SESSION ENABLE PARALLEL DML

DROP TABLE "MGMT_DM_TT_4" PURGE

¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿¿, ¿¿ ¿¿ ¿

declare

adj number:=0;

num number:=0;

begin

select length(count(*)) into adj from (select distinct "PHONE_NUMBER" from "HR"."EMPLOYEES");

num := adj;

adj := greatest(adj - 3, 0);

execute immediate 'create table MGMT_DM_TT_4

 

(orig_val null, new_val null) NOLOGGING PARALLEL as

select CAST(null AS VARCHAR2(20)) orig_val, CAST(null AS VARCHAR2(20)) new_val from dual union all

select s.orig_val,

case

when s.subset = 1 then

CAST(

lpad(3 + n

vl(substr(s.new_num, 1, 1), 0), 1, 0)

AS VARCHAR2(20))

end new_val

from (select rownum rn, orig_val, subset, rid, lpad(rownum - 1, '||num||', 0) new_num

from (select "PHONE_NUMBER" orig_val, min(rowid) rid, min(

case

when 1=1 then 1

end

) subset

from "HR"."EMPLOYEES" group by "PHONE_NUMBER")) s

where 1=1 and s.orig_val is not null

';

DBMS_STATS.GATHER_TABLE_STATS(NULL, '"MGMT_DM_TT_4"', estimate_percent=>DBMS_STATS.AUTO_SAMPLE_

SIZE, degree=>DBMS_STATS.DEFAULT_DEGREE);

end;

DROP TRIGGER "HR"."SECURE_EMPLOYEES"

DROP TRIGGER "HR"."UPDATE_JOB_HISTORY"

DECLARE

CURSOR fk_sql IS select refr.owner, refr.table_name, refr.constraint_name

from dba_constraints refd, dba_constraints refr

where refd.owner = 'HR' and

refd.table_name = 'EMPLOYEES' and

refr.constraint_ty

pe = 'R' and

refr.r_owner = refd.owner and

refr.r_constraint_name = refd.constraint_name;

BEGIN

FOR fk IN fk_sql

LOOP

EXECUTE IMMEDIATE 'ALTER TABLE "' || fk.owner || '"."' ||

fk.table_name || '" DROP CONSTRAINT "

' || fk.constraint_name || '"';

END LOOP;

END;

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿ ¿:

CREATE OR REPLACE procedure "HR".MGMT$MASK_GRANT_3 AS

grant_cur INTEGER;

BEGIN

grant_cur := DBMS_SQL.OPEN_CURSOR;

DBMS_SQL.PARSE (grant_cur, ' REVOKE REFERENCES ON "HR"."EMPLOYEES" FR

OM "OE"', DBMS_SQL.NATIVE);

DBMS_SQL.CLOSE_CURSOR (grant_cur);

END;

BEGIN "HR".MGMT$MASK_GRANT_3; END;

DROP procedure "HR".MGMT$MASK_GRANT_3

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿ ¿:

CREATE OR REPLACE procedure "HR".MGMT$MASK_GRANT_3 AS

grant_cur INTEGER;

BEGIN

grant_cur := DBMS_SQL.OPEN_CURSOR;

DBMS_SQL.PARSE (grant_cur, ' REVOKE SELECT ON "HR"."EMPLOYEES" FROM "

OE"', DBMS_SQL.NATIVE);

DBMS_SQL.CLOSE_CURSOR (grant_cur);

END;

BEGIN "HR".MGMT$MASK_GRANT_3; END;

DROP procedure "HR".MGMT$MASK_GRANT_3

DECLARE

CURSOR c_sql IS select owner, table_name, constraint_name,

constraint_type, generated, index_name from dba_constraints

where owner = 'HR' and

table_name = 'EMPLOYEES' and

constraint_type <> 'R';

BEGIN

FOR c I

N c_sql

LOOP

EXECUTE IMMEDIATE 'ALTER TABLE "' || c.owner || '"."' ||

c.table_name || '" DROP CONSTRAINT "' || c.constraint_name || '"';

END LOOP;

END;

DROP INDEX "HR"."EMP_DEPARTMENT_IX"

DROP INDEX "HR"."EMP_EMAIL_UK"

DROP INDEX "HR"."EMP_EMP_ID_PK"

DROP INDEX "HR"."EMP_JOB_IX"

DROP INDEX "HR"."EMP_MANAGER_IX"

DROP INDEX "HR"."EMP_NAME_IX"

ALTER TABLE "HR"."EMPLOYEES" RENAME TO "EMPLOYEES$DMASK"

CREATE TABLE "HR"."EMPLOYEES" TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 1 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING NOCOMPRESS PARALLEL AS SELECT s."EMPLOYEE_ID", s."FIRST_NAME", s."LAST_NAME", s."EMAIL", c0m4.NEW_VAL "PHONE_N

UMBER", s."HIRE_DATE", s."JOB_ID", s."SALARY", s."COMMISSION_PCT", s."MANAGER_ID", s."DEPARTMENT_ID" FROM "HR"."EMPLOYEES$DMASK" s , MGMT_DM_TT_4 c0m4 WHERE sys_op_map_nonnull(s."PHONE_NUMBER") = sys_op_map_nonnull(c0m4.ORIG_VAL)

ALTER TABLE "HR"."EMPLOYEES" NOPARALLEL

DROP TABLE "HR"."EMPLOYEES$DMASK" PURGE

CREATE INDEX "HR"."EMP_DEPARTMENT_IX" ON "HR"."EMPLOYEES" ("DEPARTMENT_ID") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

CREATE UNIQUE INDEX "HR"."EMP_EMAIL_UK" ON "HR"."EMPLOYEES" ("EMAIL") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

CREATE UNIQUE INDEX "HR"."EMP_EMP_ID_PK" ON "HR"."EMPLOYEES" ("EMPLOYEE_ID") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

CREATE INDEX "HR"."EMP_JOB_IX" ON "HR"."EMPLOYEES" ("JOB_ID") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

CREATE INDEX "HR"."EMP_MANAGER_IX" ON "HR"."EMPLOYEES" ("MANAGER_ID") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

CREATE INDEX "HR"."EMP_NAME_IX" ON "HR"."EMPLOYEES" ("LAST_NAME", "FIRST_NAME") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

   

ALTER TABLE "HR"."EMPLOYEES" MODIFY ("EMAIL" CONSTRAINT "EMP_EMAIL_NN" NOT NULL )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_EMAIL_UK" UNIQUE ("EMAIL") )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_EMP_ID_PK" PRIMARY KEY ("EMPLOYEE_ID") )

ALTER TABLE "HR"."EMPLOYEES" MODIFY ("HIRE_DATE" CONSTRAINT "EMP_HIRE_DATE_NN" NOT NULL )

ALTER TABLE "HR"."EMPLOYEES" MODIFY ("JOB_ID" CONSTRAINT "EMP_JOB_NN" NOT NULL )

ALTER TABLE "HR"."EMPLOYEES" MODIFY ("LAST_NAME" CONSTRAINT "EMP_LAST_NAME_NN" NOT NULL )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_SALARY_MIN" CHECK (salary > 0) )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_MANAGER_FK" FOREIGN KEY ("MANAGER_ID") REFERENCES "HR"."EMPLOYEES" ("EMPLOYEE_ID") )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_DEPT_FK" FOREIGN KEY ("DEPARTMENT_ID") REFERENCES "HR"."DEPARTMENTS" ("DEPARTMENT_ID") )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_JOB_FK" FOREIGN KEY ("JOB_ID") REFERENCES "HR"."JOBS" ("JOB_ID") )

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿ ¿:

CREATE OR REPLACE procedure "HR".MGMT$MASK_GRANT_3 AS

grant_cur INTEGER;

BEGIN

grant_cur := DBMS_SQL.OPEN_CURSOR;

DBMS_SQL.PARSE (grant_cur, ' GRANT REFERENCES ON "HR"."EMPLOYEES" TO

"OE"', DBMS_SQL.NATIVE);

DBMS_SQL.CLOSE_CURSOR (grant_cur);

END;

BEGIN "HR".MGMT$MASK_GRANT_3; END;

DROP procedure "HR".MGMT$MASK_GRANT_3

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿ ¿:

CREATE OR REPLACE procedure "HR".MGMT$MASK_GRANT_3 AS

grant_cur INTEGER;

BEGIN

grant_cur := DBMS_SQL.OPEN_CURSOR;

DBMS_SQL.PARSE (grant_cur, ' GRANT SELECT ON "HR"."EMPLOYEES" TO "OE"

', DBMS_SQL.NATIVE);

DBMS_SQL.CLOSE_CURSOR (grant_cur);

END;

BEGIN "HR".MGMT$MASK_GRANT_3; END;

DROP procedure "HR".MGMT$MASK_GRANT_3

ALTER TABLE "HR"."DEPARTMENTS" ADD (CONSTRAINT "DEPT_MGR_FK" FOREIGN KEY ("MANAGER_ID") REFERENCES "HR"."EMPLOYEES" ("EMPLOYEE_ID") )

ALTER TABLE "HR"."JOB_HISTORY" ADD (CONSTRAINT "JHIST_EMP_FK" FOREIGN KEY ("EMPLOYEE_ID") REFERENCES "HR"."EMPLOYEES" ("EMPLOYEE_ID") )

ALTER TABLE "OE"."CUSTOMERS" ADD (CONSTRAINT "CUSTOMERS_ACCOUNT_MANAGER_FK" FOREIGN KEY ("ACCOUNT_MGR_ID") REFERENCES "HR"."EMPLOYEES" ("EMPLOYEE_ID") ON DELETE SET NULL)

ALTER TABLE "OE"."ORDERS" ADD (CONSTRAINT "ORDERS_SALES_REP_FK" FOREIGN KEY ("SALES_REP_ID") REFERENCES "HR"."EMPLOYEES" ("EMPLOYEE_ID") ON DELETE SET NULL)

CREATE OR REPLACE TRIGGER "HR"."SECURE_EMPLOYEES" BEFORE

INSERT

OR UPDATE

OR DELETE ON "HR"."EMPLOYEES" BEGIN

secure_dml;

END secure_employees;

ALTER TRIGGER "HR"."SECURE_EMPLOYEES" DISABLE

CREATE OR REPLACE TRIGGER "HR"."UPDATE_JOB_HISTORY" AFTER

UPDATE OF "DEPARTMENT_ID", "JOB_ID" ON "HR"."EMPLOYEES" REFERENCING OLD AS OLD NEW AS NEW FOR EACH ROW BEGIN

add_job_history(:old.employee_id, :old.hire_date, sysdate,

:old.job_

id, :old.department_id);

END;

ALTER VIEW "HR"."EMP_DETAILS_VIEW" COMPILE

COMMENT ON COLUMN "HR"."EMPLOYEES"."COMMISSION_PCT" IS 'Commission percentage of the employee; Only employees in sales

department elgible for commission percentage'

COMMENT ON COLUMN "HR"."EMPLOYEES"."DEPARTMENT_ID" IS 'Department id where employee works; foreign key to department_id

column of the departments table'

COMMENT ON COLUMN "HR"."EMPLOYEES"."EMAIL" IS 'Email id of the employee'

COMMENT ON COLUMN "HR"."EMPLOYEES"."EMPLOYEE_ID" IS 'Primary key of employees table.'

COMMENT ON COLUMN "HR"."EMPLOYEES"."FIRST_NAME" IS 'First name of the employee. A not null column.'

COMMENT ON COLUMN "HR"."EMPLOYEES"."HIRE_DATE" IS 'Date when the employee started on this job. A not null column.'

COMMENT ON COLUMN "HR"."EMPLOYEES"."JOB_ID" IS 'Current job of the employee; foreign key to job_id column of the

jobs table. A not null column.'

COMMENT ON COLUMN "HR"."EMPLOYEES"."LAST_NAME" IS 'Last name of the employee. A not null column.'

COMMENT ON COLUMN "HR"."EMPLOYEES"."MANAGER_ID" IS 'Manager id of the employee; has same domain as manager_id in

departments table. Foreign key to employee_id column of employees table.

(useful for reflexive joins and CONNECT BY query)'

COMMENT ON COLUMN "HR"."EMPLOYEES"."PHONE_NUMBER" IS 'Phone number of the employee; includes country code and area code'

COMMENT ON COLUMN "HR"."EMPLOYEES"."SALARY" IS 'Monthly salary of the employee. Must be greater

than zero (enforced by constraint emp_salary_min)'

COMMENT ON TABLE "HR"."EMPLOYEES" IS 'employees table. Contains 107 rows. References with departments,

jobs, job_history tables. Contains a self reference.'

BEGIN DBMS_STATS.GATHER_TABLE_STATS('"HR"', '"EMPLOYEES"', estimate_percent=>DBMS_STATS.AUTO_SAMPLE_SIZE, degree=>DBMS_STATS.DEFAULT_DEGREE, cascade=>TRUE); END;

¿¿¿ ¿¿¿¿ ¿¿¿¿¿¿¿. ¿¿ ¿¿¿ ¿¿¿¿¿.

¿¿ ¿¿¿ ¿¿¿ ¿¿ ¿

¿¿ ¿¿¿ ¿¿¿¿ ¿¿¿

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿

¿¿¿ ¿¿¿¿ ¿¿¿¿ ¿¿¿

¿¿¿¿ ¿¿ ¿¿

SQL> set ver on

   

2.No Unique Index

2-1 중복된 값 없도록 Data Masking

   

  • 해당컬럼 선택(First_name) : no unique index

   

   

  • 현재 데이터 상태

   

  • Data Masking 설정(섞기): 해당 열의 값들끼리 섞어버림

  • 변경된 데이터

   

   

   

  • 현재상태 확인
    • Constraints/Index 에 아무 이상이 없다.

   

   

   

<실행된 스크립트내역>

-- ¿¿ ¿¿¿¿¿¿: test

-- ¿¿¿¿ ¿¿ ¿¿: 03-9¿ -2012 13:30

¿¿¿ ¿¿¿ ¿¿ ¿

User is "SYS"

COMMIT

ALTER SESSION ENABLE PARALLEL DML

DROP TABLE "MGMT_DM_TT_7" PURGE

¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿¿, ¿¿ ¿¿ ¿

declare

adj number:=0;

num number:=0;

begin

select length(count(*)) into adj from (select distinct "FIRST_NAME" from "HR"."EMPLOYEES");

num := adj;

adj := greatest(adj - 2, 0);

execute immediate 'create table MGMT_DM_TT_7

(

orig_val null, new_val null) NOLOGGING PARALLEL as

select CAST(null AS VARCHAR2(20)) orig_val, CAST(null AS VARCHAR2(20)) new_val from dual union all

select s.orig_val,

case

when s.subset = 1 then

CAST(

a0.new_val

 

AS VARCHAR2(20))

end new_val

from (select rownum rn, orig_val, subset, rid, lpad(rownum - 1, '||num||', 0) new_num

from (select "FIRST_NAME" orig_val, min(rowid) rid, min(

case

when 1=1 then 1

end

 

) subset

from "HR"."EMPLOYEES" group by "FIRST_NAME")) s

,(select rownum rn, new_val from (select distinct "FIRST_NAME" new_val from "HR"."EMPLOYEES" where 1=1 order by dbms_random.value)) a0

where 1=1 and s.orig_val is not null

 

and s.rn = a0.rn

';

DBMS_STATS.GATHER_TABLE_STATS(NULL, '"MGMT_DM_TT_7"', estimate_percent=>DBMS_STATS.AUTO_SAMPLE_SIZE, degree=>DBMS_STATS.DEFAULT_DEGREE);

end;

DROP TRIGGER "HR"."UPDATE_JOB_HISTORY"

DROP TRIGGER "HR"."SECURE_EMPLOYEES"

DECLARE

CURSOR fk_sql IS select refr.owner, refr.table_name, refr.constraint_name

from dba_constraints refd, dba_constraints refr

where refd.owner = 'HR' and

refd.table_name = 'EMPLOYEES' and

refr.constraint_ty

pe = 'R' and

refr.r_owner = refd.owner and

refr.r_constraint_name = refd.constraint_name;

BEGIN

FOR fk IN fk_sql

LOOP

EXECUTE IMMEDIATE 'ALTER TABLE "' || fk.owner || '"."' ||

fk.table_name || '" DROP CONSTRAINT "

' || fk.constraint_name || '"';

END LOOP;

END;

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿ ¿:

CREATE OR REPLACE procedure "HR".MGMT$MASK_GRANT_6 AS

grant_cur INTEGER;

BEGIN

grant_cur := DBMS_SQL.OPEN_CURSOR;

DBMS_SQL.PARSE (grant_cur, ' REVOKE REFERENCES ON "HR"."EMPLOYEES" FR

OM "OE"', DBMS_SQL.NATIVE);

DBMS_SQL.CLOSE_CURSOR (grant_cur);

END;

BEGIN "HR".MGMT$MASK_GRANT_6; END;

DROP procedure "HR".MGMT$MASK_GRANT_6

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿ ¿:

CREATE OR REPLACE procedure "HR".MGMT$MASK_GRANT_6 AS

grant_cur INTEGER;

BEGIN

grant_cur := DBMS_SQL.OPEN_CURSOR;

DBMS_SQL.PARSE (grant_cur, ' REVOKE SELECT ON "HR"."EMPLOYEES" FROM "

OE"', DBMS_SQL.NATIVE);

DBMS_SQL.CLOSE_CURSOR (grant_cur);

END;

BEGIN "HR".MGMT$MASK_GRANT_6; END;

DROP procedure "HR".MGMT$MASK_GRANT_6

DECLARE

CURSOR c_sql IS select owner, table_name, constraint_name,

constraint_type, generated, index_name from dba_constraints

where owner = 'HR' and

table_name = 'EMPLOYEES' and

constraint_type <> 'R';

BEGIN

FOR c I

N c_sql

LOOP

EXECUTE IMMEDIATE 'ALTER TABLE "' || c.owner || '"."' ||

c.table_name || '" DROP CONSTRAINT "' || c.constraint_name || '"';

END LOOP;

END;

DROP INDEX "HR"."EMP_DEPARTMENT_IX"

DROP INDEX "HR"."EMP_EMAIL_UK"

DROP INDEX "HR"."EMP_EMP_ID_PK"

DROP INDEX "HR"."EMP_JOB_IX"

DROP INDEX "HR"."EMP_MANAGER_IX"

DROP INDEX "HR"."EMP_NAME_IX"

ALTER TABLE "HR"."EMPLOYEES" RENAME TO "EMPLOYEES$DMASK"

CREATE TABLE "HR"."EMPLOYEES" TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 1 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING NOCOMPRESS PARALLEL AS SELECT s."EMPLOYEE_ID", c0m7.NEW_VAL "FIRST_NAME", s."LAST_NAME", s."EMAIL", s."PHONE_N

UMBER", s."HIRE_DATE", s."JOB_ID", s."SALARY", s."COMMISSION_PCT", s."MANAGER_ID", s."DEPARTMENT_ID" FROM "HR"."EMPLOYEES$DMASK" s , MGMT_DM_TT_7 c0m7 WHERE sys_op_map_nonnull(s."FIRST_NAME") = sys_op_map_nonnull(c0m7.ORIG_VAL)

ALTER TABLE "HR"."EMPLOYEES" NOPARALLEL

DROP TABLE "HR"."EMPLOYEES$DMASK" PURGE

CREATE INDEX "HR"."EMP_DEPARTMENT_IX" ON "HR"."EMPLOYEES" ("DEPARTMENT_ID") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

CREATE UNIQUE INDEX "HR"."EMP_EMAIL_UK" ON "HR"."EMPLOYEES" ("EMAIL") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

CREATE UNIQUE INDEX "HR"."EMP_EMP_ID_PK" ON "HR"."EMPLOYEES" ("EMPLOYEE_ID") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

CREATE INDEX "HR"."EMP_JOB_IX" ON "HR"."EMPLOYEES" ("JOB_ID") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

CREATE INDEX "HR"."EMP_MANAGER_IX" ON "HR"."EMPLOYEES" ("MANAGER_ID") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

CREATE INDEX "HR"."EMP_NAME_IX" ON "HR"."EMPLOYEES" ("LAST_NAME", "FIRST_NAME") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

ALTER TABLE "HR"."EMPLOYEES" MODIFY ("EMAIL" CONSTRAINT "EMP_EMAIL_NN" NOT NULL )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_EMAIL_UK" UNIQUE ("EMAIL") )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_EMP_ID_PK" PRIMARY KEY ("EMPLOYEE_ID") )

ALTER TABLE "HR"."EMPLOYEES" MODIFY ("HIRE_DATE" CONSTRAINT "EMP_HIRE_DATE_NN" NOT NULL )

ALTER TABLE "HR"."EMPLOYEES" MODIFY ("JOB_ID" CONSTRAINT "EMP_JOB_NN" NOT NULL )

ALTER TABLE "HR"."EMPLOYEES" MODIFY ("LAST_NAME" CONSTRAINT "EMP_LAST_NAME_NN" NOT NULL )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_SALARY_MIN" CHECK (salary > 0) )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_MANAGER_FK" FOREIGN KEY ("MANAGER_ID") REFERENCES "HR"."EMPLOYEES" ("EMPLOYEE_ID") )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_DEPT_FK" FOREIGN KEY ("DEPARTMENT_ID") REFERENCES "HR"."DEPARTMENTS" ("DEPARTMENT_ID") )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_JOB_FK" FOREIGN KEY ("JOB_ID") REFERENCES "HR"."JOBS" ("JOB_ID") )

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿ ¿:

CREATE OR REPLACE procedure "HR".MGMT$MASK_GRANT_6 AS

grant_cur INTEGER;

BEGIN

grant_cur := DBMS_SQL.OPEN_CURSOR;

DBMS_SQL.PARSE (grant_cur, ' GRANT REFERENCES ON "HR"."EMPLOYEES" TO

"OE"', DBMS_SQL.NATIVE);

DBMS_SQL.CLOSE_CURSOR (grant_cur);

END;

BEGIN "HR".MGMT$MASK_GRANT_6; END;

DROP procedure "HR".MGMT$MASK_GRANT_6

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿ ¿:

CREATE OR REPLACE procedure "HR".MGMT$MASK_GRANT_6 AS

grant_cur INTEGER;

BEGIN

grant_cur := DBMS_SQL.OPEN_CURSOR;

DBMS_SQL.PARSE (grant_cur, ' GRANT SELECT ON "HR"."EMPLOYEES" TO "OE"

', DBMS_SQL.NATIVE);

DBMS_SQL.CLOSE_CURSOR (grant_cur);

END;

BEGIN "HR".MGMT$MASK_GRANT_6; END;

DROP procedure "HR".MGMT$MASK_GRANT_6

ALTER TABLE "HR"."DEPARTMENTS" ADD (CONSTRAINT "DEPT_MGR_FK" FOREIGN KEY ("MANAGER_ID") REFERENCES "HR"."EMPLOYEES" ("EMPLOYEE_ID") )

ALTER TABLE "HR"."JOB_HISTORY" ADD (CONSTRAINT "JHIST_EMP_FK" FOREIGN KEY ("EMPLOYEE_ID") REFERENCES "HR"."EMPLOYEES" ("EMPLOYEE_ID") )

ALTER TABLE "OE"."CUSTOMERS" ADD (CONSTRAINT "CUSTOMERS_ACCOUNT_MANAGER_FK" FOREIGN KEY ("ACCOUNT_MGR_ID") REFERENCES "HR"."EMPLOYEES" ("EMPLOYEE_ID") ON DELETE SET NULL)

ALTER TABLE "OE"."ORDERS" ADD (CONSTRAINT "ORDERS_SALES_REP_FK" FOREIGN KEY ("SALES_REP_ID") REFERENCES "HR"."EMPLOYEES" ("EMPLOYEE_ID") ON DELETE SET NULL)

CREATE OR REPLACE TRIGGER "HR"."UPDATE_JOB_HISTORY" AFTER

UPDATE OF "DEPARTMENT_ID", "JOB_ID" ON "HR"."EMPLOYEES" REFERENCING OLD AS OLD NEW AS NEW FOR EACH ROW BEGIN

add_job_history(:old.employee_id, :old.hire_date, sysdate,

:old.job_

id, :old.department_id);

END;

ALTER VIEW "HR"."EMP_DETAILS_VIEW" COMPILE

CREATE OR REPLACE TRIGGER "HR"."SECURE_EMPLOYEES" BEFORE

INSERT

OR UPDATE

OR DELETE ON "HR"."EMPLOYEES" BEGIN

secure_dml;

END secure_employees;

ALTER TRIGGER "HR"."SECURE_EMPLOYEES" DISABLE

COMMENT ON COLUMN "HR"."EMPLOYEES"."COMMISSION_PCT" IS 'Commission percentage of the employee; Only employees in sales

department elgible for commission percentage'

COMMENT ON COLUMN "HR"."EMPLOYEES"."DEPARTMENT_ID" IS 'Department id where employee works; foreign key to department_id

column of the departments table'

COMMENT ON COLUMN "HR"."EMPLOYEES"."EMAIL" IS 'Email id of the employee'

COMMENT ON COLUMN "HR"."EMPLOYEES"."EMPLOYEE_ID" IS 'Primary key of employees table.'

COMMENT ON COLUMN "HR"."EMPLOYEES"."FIRST_NAME" IS 'First name of the employee. A not null column.'

COMMENT ON COLUMN "HR"."EMPLOYEES"."HIRE_DATE" IS 'Date when the employee started on this job. A not null column.'

COMMENT ON COLUMN "HR"."EMPLOYEES"."JOB_ID" IS 'Current job of the employee; foreign key to job_id column of the

jobs table. A not null column.'

COMMENT ON COLUMN "HR"."EMPLOYEES"."LAST_NAME" IS 'Last name of the employee. A not null column.'

COMMENT ON COLUMN "HR"."EMPLOYEES"."MANAGER_ID" IS 'Manager id of the employee; has same domain as manager_id in

departments table. Foreign key to employee_id column of employees table.

(useful for reflexive joins and CONNECT BY query)'

COMMENT ON COLUMN "HR"."EMPLOYEES"."PHONE_NUMBER" IS 'Phone number of the employee; includes country code and area code'

COMMENT ON COLUMN "HR"."EMPLOYEES"."SALARY" IS 'Monthly salary of the employee. Must be greater

than zero (enforced by constraint emp_salary_min)'

COMMENT ON TABLE "HR"."EMPLOYEES" IS 'employees table. Contains 107 rows. References with departments,

jobs, job_history tables. Contains a self reference.'

BEGIN DBMS_STATS.GATHER_TABLE_STATS('"HR"', '"EMPLOYEES"', estimate_percent=>DBMS_STATS.AUTO_SAMPLE_SIZE, degree=>DBMS_STATS.DEFAULT_DEGREE, cascade=>TRUE); END;

¿¿¿ ¿¿¿¿ ¿¿¿¿¿¿¿. ¿¿ ¿¿¿ ¿¿¿¿¿.

¿¿ ¿¿¿ ¿¿¿ ¿¿ ¿

¿¿ ¿¿¿ ¿¿¿¿ ¿¿¿

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿

¿¿¿ ¿¿¿¿ ¿¿¿¿ ¿¿¿

¿¿¿¿ ¿¿ ¿¿

SQL> set ver on

   

   

2-2 중복된 값이 있도록 Data Masking

   

  • 컬럼 선택(LAST_NAME): no Unique index

       

       

  • 현재 데이터 상태확인

       

  • Data Masking 옵션 선택(무작위 문자열): 2자리의 무작위로 문자열 삽입

   

  • 변경된 데이터 확인

   

  • 상태 확인
  • 중복된 값이 있어도 no Uinque index이기 때문에 Constraints/Index에 이상 없음

       

   

   

<수행 스크립트 확인>

<file_error msg="지정된 경로를 찾을 수 없습니다." n="3"/>

-- ¿¿ ¿¿¿¿¿¿: test

-- ¿¿¿¿ ¿¿ ¿¿: 03-9¿ -2012 14:19

¿¿¿ ¿¿¿ ¿¿ ¿

User is "SYS"

COMMIT

ALTER SESSION ENABLE PARALLEL DML

DROP TABLE "MGMT_DM_TT_42" PURGE

¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿¿, ¿¿ ¿¿ ¿

declare

adj number:=0;

num number:=0;

begin

select length(count(*)) into adj from (select distinct "LAST_NAME" from "HR"."EMPLOYEES");

num := adj;

adj := greatest(adj - 1, 0);

execute immediate 'create table MGMT_DM_TT_42

(

orig_val null, new_val null) NOLOGGING PARALLEL as

select CAST(null AS VARCHAR2(25)) orig_val, CAST(null AS VARCHAR2(25)) new_val from dual union all

select s.orig_val,

case

when s.subset = 1 then

CAST(

lpad(lower(d

bms_random.string(''l'', trunc(dbms_random.value(1, 1 - least(1, greatest('||adj||' - 0, 0)))))), 1 - least(1, greatest('||adj||' - 0, 0)),''a'')

|| mgmt$mask_randomencode(nvl(substr(s.new_num, 1, 1 + least(1, greatest('||adj||' - 0, 0))), ''0''),

1 + least(1, greatest('||adj||' - 0, 0)))

AS VARCHAR2(25))

end new_val

from (select rownum rn, orig_val, subset, rid, lpad(rownum - 1, '||num||', 0) new_num

from (select "LAST_NAME" orig_val, min(rowid) rid, min(

case

   

when 1=1 then 1

end

) subset

from "HR"."EMPLOYEES" group by "LAST_NAME")) s

where 1=1 and s.orig_val is not null

';

DBMS_STATS.GATHER_TABLE_STATS(NULL, '"MGMT_DM_TT_42"', estimate_percent=>DBMS_STATS.AUTO_SAMPLE_S

IZE, degree=>DBMS_STATS.DEFAULT_DEGREE);

end;

DECLARE

CURSOR fk_sql IS select refr.owner, refr.table_name, refr.constraint_name

from dba_constraints refd, dba_constraints refr

where refd.owner = 'HR' and

refd.table_name = 'EMPLOYEES' and

refr.constraint_ty

pe = 'R' and

refr.r_owner = refd.owner and

refr.r_constraint_name = refd.constraint_name;

BEGIN

FOR fk IN fk_sql

LOOP

EXECUTE IMMEDIATE 'ALTER TABLE "' || fk.owner || '"."' ||

fk.table_name || '" DROP CONSTRAINT "

' || fk.constraint_name || '"';

END LOOP;

END;

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿ ¿:

CREATE OR REPLACE procedure "HR".MGMT$MASK_GRANT_41 AS

grant_cur INTEGER;

BEGIN

grant_cur := DBMS_SQL.OPEN_CURSOR;

DBMS_SQL.PARSE (grant_cur, ' REVOKE REFERENCES ON "HR"."EMPLOYEES" F

ROM "OE"', DBMS_SQL.NATIVE);

DBMS_SQL.CLOSE_CURSOR (grant_cur);

END;

BEGIN "HR".MGMT$MASK_GRANT_41; END;

DROP procedure "HR".MGMT$MASK_GRANT_41

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿ ¿:

CREATE OR REPLACE procedure "HR".MGMT$MASK_GRANT_41 AS

grant_cur INTEGER;

BEGIN

grant_cur := DBMS_SQL.OPEN_CURSOR;

DBMS_SQL.PARSE (grant_cur, ' REVOKE SELECT ON "HR"."EMPLOYEES" FROM

"OE"', DBMS_SQL.NATIVE);

DBMS_SQL.CLOSE_CURSOR (grant_cur);

END;

BEGIN "HR".MGMT$MASK_GRANT_41; END;

DROP procedure "HR".MGMT$MASK_GRANT_41

DECLARE

CURSOR c_sql IS select owner, table_name, constraint_name,

constraint_type, generated, index_name from dba_constraints

where owner = 'HR' and

table_name = 'EMPLOYEES' and

constraint_type <> 'R';

BEGIN

FOR c I

N c_sql

LOOP

EXECUTE IMMEDIATE 'ALTER TABLE "' || c.owner || '"."' ||

c.table_name || '" DROP CONSTRAINT "' || c.constraint_name || '"';

END LOOP;

END;

DROP INDEX "HR"."EMP_DEPARTMENT_IX"

DROP INDEX "HR"."EMP_EMAIL_UK"

DROP INDEX "HR"."EMP_EMP_ID_PK"

DROP INDEX "HR"."EMP_JOB_IX"

DROP INDEX "HR"."EMP_MANAGER_IX"

DROP INDEX "HR"."EMP_NAME_IX"

ALTER TABLE "HR"."EMPLOYEES" RENAME TO "EMPLOYEES$DMASK"

CREATE TABLE "HR"."EMPLOYEES" TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 1 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING NOCOMPRESS PARALLEL AS SELECT s."EMPLOYEE_ID", s."FIRST_NAME", c0m42.NEW_VAL "LAST_NAME", s."EMAIL", s."PHONE_

NUMBER", s."HIRE_DATE", s."JOB_ID", s."SALARY", s."COMMISSION_PCT", s."MANAGER_ID", s."DEPARTMENT_ID" FROM "HR"."EMPLOYEES$DMASK" s , MGMT_DM_TT_42 c0m42 WHERE sys_op_map_nonnull(s."LAST_NAME") = sys_op_map_nonnull(c0m42.ORIG_VAL)

ALTER TABLE "HR"."EMPLOYEES" NOPARALLEL

DROP TABLE "HR"."EMPLOYEES$DMASK" PURGE

CREATE INDEX "HR"."EMP_DEPARTMENT_IX" ON "HR"."EMPLOYEES" ("DEPARTMENT_ID") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

CREATE UNIQUE INDEX "HR"."EMP_EMAIL_UK" ON "HR"."EMPLOYEES" ("EMAIL") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

CREATE UNIQUE INDEX "HR"."EMP_EMP_ID_PK" ON "HR"."EMPLOYEES" ("EMPLOYEE_ID") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

CREATE INDEX "HR"."EMP_JOB_IX" ON "HR"."EMPLOYEES" ("JOB_ID") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

CREATE INDEX "HR"."EMP_MANAGER_IX" ON "HR"."EMPLOYEES" ("MANAGER_ID") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

CREATE INDEX "HR"."EMP_NAME_IX" ON "HR"."EMPLOYEES" ("LAST_NAME", "FIRST_NAME") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

ALTER TABLE "HR"."EMPLOYEES" MODIFY ("EMAIL" CONSTRAINT "EMP_EMAIL_NN" NOT NULL )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_EMAIL_UK" UNIQUE ("EMAIL") )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_EMP_ID_PK" PRIMARY KEY ("EMPLOYEE_ID") )

ALTER TABLE "HR"."EMPLOYEES" MODIFY ("HIRE_DATE" CONSTRAINT "EMP_HIRE_DATE_NN" NOT NULL )

ALTER TABLE "HR"."EMPLOYEES" MODIFY ("JOB_ID" CONSTRAINT "EMP_JOB_NN" NOT NULL )

ALTER TABLE "HR"."EMPLOYEES" MODIFY ("LAST_NAME" CONSTRAINT "EMP_LAST_NAME_NN" NOT NULL )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_SALARY_MIN" CHECK (salary > 0) )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_MANAGER_FK" FOREIGN KEY ("MANAGER_ID") REFERENCES "HR"."EMPLOYEES" ("EMPLOYEE_ID") )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_DEPT_FK" FOREIGN KEY ("DEPARTMENT_ID") REFERENCES "HR"."DEPARTMENTS" ("DEPARTMENT_ID") )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_JOB_FK" FOREIGN KEY ("JOB_ID") REFERENCES "HR"."JOBS" ("JOB_ID") )

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿ ¿:

CREATE OR REPLACE procedure "HR".MGMT$MASK_GRANT_41 AS

grant_cur INTEGER;

BEGIN

grant_cur := DBMS_SQL.OPEN_CURSOR;

DBMS_SQL.PARSE (grant_cur, ' GRANT REFERENCES ON "HR"."EMPLOYEES" TO

"OE"', DBMS_SQL.NATIVE);

DBMS_SQL.CLOSE_CURSOR (grant_cur);

END;

BEGIN "HR".MGMT$MASK_GRANT_41; END;

DROP procedure "HR".MGMT$MASK_GRANT_41

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿ ¿:

CREATE OR REPLACE procedure "HR".MGMT$MASK_GRANT_41 AS

grant_cur INTEGER;

BEGIN

grant_cur := DBMS_SQL.OPEN_CURSOR;

DBMS_SQL.PARSE (grant_cur, ' GRANT SELECT ON "HR"."EMPLOYEES" TO "OE

"', DBMS_SQL.NATIVE);

DBMS_SQL.CLOSE_CURSOR (grant_cur);

END;

BEGIN "HR".MGMT$MASK_GRANT_41; END;

DROP procedure "HR".MGMT$MASK_GRANT_41

COMMENT ON COLUMN "HR"."EMPLOYEES"."COMMISSION_PCT" IS 'Commission percentage of the employee; Only employees in sales

department elgible for commission percentage'

COMMENT ON COLUMN "HR"."EMPLOYEES"."DEPARTMENT_ID" IS 'Department id where employee works; foreign key to department_id

column of the departments table'

COMMENT ON COLUMN "HR"."EMPLOYEES"."EMAIL" IS 'Email id of the employee'

COMMENT ON COLUMN "HR"."EMPLOYEES"."EMPLOYEE_ID" IS 'Primary key of employees table.'

COMMENT ON COLUMN "HR"."EMPLOYEES"."FIRST_NAME" IS 'First name of the employee. A not null column.'

COMMENT ON COLUMN "HR"."EMPLOYEES"."HIRE_DATE" IS 'Date when the employee started on this job. A not null column.'

COMMENT ON COLUMN "HR"."EMPLOYEES"."JOB_ID" IS 'Current job of the employee; foreign key to job_id column of the

jobs table. A not null column.'

COMMENT ON COLUMN "HR"."EMPLOYEES"."LAST_NAME" IS 'Last name of the employee. A not null column.'

COMMENT ON COLUMN "HR"."EMPLOYEES"."MANAGER_ID" IS 'Manager id of the employee; has same domain as manager_id in

departments table. Foreign key to employee_id column of employees table.

(useful for reflexive joins and CONNECT BY query)'

COMMENT ON COLUMN "HR"."EMPLOYEES"."PHONE_NUMBER" IS 'Phone number of the employee; includes country code and area code'

COMMENT ON COLUMN "HR"."EMPLOYEES"."SALARY" IS 'Monthly salary of the employee. Must be greater

than zero (enforced by constraint emp_salary_min)'

COMMENT ON TABLE "HR"."EMPLOYEES" IS 'employees table. Contains 107 rows. References with departments,

jobs, job_history tables. Contains a self reference.'

BEGIN DBMS_STATS.GATHER_TABLE_STATS('"HR"', '"EMPLOYEES"', estimate_percent=>DBMS_STATS.AUTO_SAMPLE_SIZE, degree=>DBMS_STATS.DEFAULT_DEGREE, cascade=>TRUE); END;

¿¿¿ ¿¿¿¿ ¿¿¿¿¿¿¿. ¿¿ ¿¿¿ ¿¿¿¿¿.

¿¿ ¿¿¿ ¿¿¿ ¿¿ ¿

¿¿ ¿¿¿ ¿¿¿¿ ¿¿¿

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿

¿¿¿ ¿¿¿¿ ¿¿¿¿ ¿¿¿

¿¿¿¿ ¿¿ ¿¿

SQL> set ver on

   

3.Yes Unique Index

3-1 중복 값이 없는 Data Masking

   

  • 대상 컬럼(EMAIL) : Unique Index

       

       

  • 원본 데이터 확인

   

  • Data Masking 옵션선택(해당 열의 Data를 섞는다.)

   

  • Data Masking 후 변경된 데이터

   

  • 상태확인
  • 중복된 값이 없이 Data Masking 되어서 기존의 Index와 Constraints가 유지되는 것을 확인할 수 있습니다,

       

   

   

<수행 스크립트 확인>

-- ¿¿ ¿¿¿¿¿¿: test

-- ¿¿¿¿ ¿¿ ¿¿: 03-9¿ -2012 14:26

¿¿¿ ¿¿¿ ¿¿ ¿

User is "SYS"

COMMIT

ALTER SESSION ENABLE PARALLEL DML

DROP TABLE "MGMT_DM_TT_45" PURGE

¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿¿, ¿¿ ¿¿ ¿

declare

adj number:=0;

num number:=0;

begin

select length(count(*)) into adj from (select distinct "EMAIL" from "HR"."EMPLOYEES");

num := adj;

adj := greatest(adj - 3, 0);

execute immediate 'create table MGMT_DM_TT_45

(orig

_val null, new_val null) NOLOGGING PARALLEL as

select CAST(null AS VARCHAR2(25)) orig_val, CAST(null AS VARCHAR2(25)) new_val from dual union all

select s.orig_val,

case

when s.subset = 1 then

CAST(

a0.new_val

 

AS VARCHAR2(25))

end new_val

from (select rownum rn, orig_val, subset, rid, lpad(rownum - 1, '||num||', 0) new_num

from (select "EMAIL" orig_val, min(rowid) rid, min(

case

when 1=1 then 1

end

)

subset

from "HR"."EMPLOYEES" group by "EMAIL")) s

,(select rownum rn, new_val from (select distinct "EMAIL" new_val from "HR"."EMPLOYEES" where 1=1 order by dbms_random.value)) a0

where 1=1 and s.orig_val is not null

and s.rn = a0.rn

';

DBMS_STATS.GATHER_TABLE_STATS(NULL, '"MGMT_DM_TT_45"', estimate_percent=>DBMS_STATS.AUTO_SAMPLE_SIZE, degree=>DBMS_STATS.DEFAULT_DEGREE);

end;

DECLARE

CURSOR fk_sql IS select refr.owner, refr.table_name, refr.constraint_name

from dba_constraints refd, dba_constraints refr

where refd.owner = 'HR' and

refd.table_name = 'EMPLOYEES' and

refr.constraint_ty

pe = 'R' and

refr.r_owner = refd.owner and

refr.r_constraint_name = refd.constraint_name;

BEGIN

FOR fk IN fk_sql

LOOP

EXECUTE IMMEDIATE 'ALTER TABLE "' || fk.owner || '"."' ||

fk.table_name || '" DROP CONSTRAINT "

' || fk.constraint_name || '"';

END LOOP;

END;

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿ ¿:

CREATE OR REPLACE procedure "HR".MGMT$MASK_GRANT_44 AS

grant_cur INTEGER;

BEGIN

grant_cur := DBMS_SQL.OPEN_CURSOR;

DBMS_SQL.PARSE (grant_cur, ' REVOKE REFERENCES ON "HR"."EMPLOYEES" F

ROM "OE"', DBMS_SQL.NATIVE);

DBMS_SQL.CLOSE_CURSOR (grant_cur);

END;

BEGIN "HR".MGMT$MASK_GRANT_44; END;

DROP procedure "HR".MGMT$MASK_GRANT_44

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿ ¿:

CREATE OR REPLACE procedure "HR".MGMT$MASK_GRANT_44 AS

grant_cur INTEGER;

BEGIN

grant_cur := DBMS_SQL.OPEN_CURSOR;

DBMS_SQL.PARSE (grant_cur, ' REVOKE SELECT ON "HR"."EMPLOYEES" FROM

"OE"', DBMS_SQL.NATIVE);

DBMS_SQL.CLOSE_CURSOR (grant_cur);

END;

BEGIN "HR".MGMT$MASK_GRANT_44; END;

DROP procedure "HR".MGMT$MASK_GRANT_44

DECLARE

CURSOR c_sql IS select owner, table_name, constraint_name,

constraint_type, generated, index_name from dba_constraints

where owner = 'HR' and

table_name = 'EMPLOYEES' and

constraint_type <> 'R';

BEGIN

FOR c I

N c_sql

LOOP

EXECUTE IMMEDIATE 'ALTER TABLE "' || c.owner || '"."' ||

c.table_name || '" DROP CONSTRAINT "' || c.constraint_name || '"';

END LOOP;

END;

DROP INDEX "HR"."EMP_DEPARTMENT_IX"

DROP INDEX "HR"."EMP_EMAIL_UK"

DROP INDEX "HR"."EMP_EMP_ID_PK"

DROP INDEX "HR"."EMP_JOB_IX"

DROP INDEX "HR"."EMP_MANAGER_IX"

DROP INDEX "HR"."EMP_NAME_IX"

ALTER TABLE "HR"."EMPLOYEES" RENAME TO "EMPLOYEES$DMASK"

CREATE TABLE "HR"."EMPLOYEES" TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 1 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING NOCOMPRESS PARALLEL AS SELECT s."EMPLOYEE_ID", s."FIRST_NAME", s."LAST_NAME", c0m45.NEW_VAL "EMAIL", s."PHONE_

NUMBER", s."HIRE_DATE", s."JOB_ID", s."SALARY", s."COMMISSION_PCT", s."MANAGER_ID", s."DEPARTMENT_ID" FROM "HR"."EMPLOYEES$DMASK" s , MGMT_DM_TT_45 c0m45 WHERE sys_op_map_nonnull(s."EMAIL") = sys_op_map_nonnull(c0m45.ORIG_VAL)

ALTER TABLE "HR"."EMPLOYEES" NOPARALLEL

DROP TABLE "HR"."EMPLOYEES$DMASK" PURGE

   

CREATE INDEX "HR"."EMP_DEPARTMENT_IX" ON "HR"."EMPLOYEES" ("DEPARTMENT_ID") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

CREATE UNIQUE INDEX "HR"."EMP_EMAIL_UK" ON "HR"."EMPLOYEES" ("EMAIL") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

CREATE UNIQUE INDEX "HR"."EMP_EMP_ID_PK" ON "HR"."EMPLOYEES" ("EMPLOYEE_ID") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

CREATE INDEX "HR"."EMP_JOB_IX" ON "HR"."EMPLOYEES" ("JOB_ID") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

CREATE INDEX "HR"."EMP_MANAGER_IX" ON "HR"."EMPLOYEES" ("MANAGER_ID") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

CREATE INDEX "HR"."EMP_NAME_IX" ON "HR"."EMPLOYEES" ("LAST_NAME", "FIRST_NAME") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

   

ALTER TABLE "HR"."EMPLOYEES" MODIFY ("EMAIL" CONSTRAINT "EMP_EMAIL_NN" NOT NULL )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_EMAIL_UK" UNIQUE ("EMAIL") )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_EMP_ID_PK" PRIMARY KEY ("EMPLOYEE_ID") )

ALTER TABLE "HR"."EMPLOYEES" MODIFY ("HIRE_DATE" CONSTRAINT "EMP_HIRE_DATE_NN" NOT NULL )

ALTER TABLE "HR"."EMPLOYEES" MODIFY ("JOB_ID" CONSTRAINT "EMP_JOB_NN" NOT NULL )

ALTER TABLE "HR"."EMPLOYEES" MODIFY ("LAST_NAME" CONSTRAINT "EMP_LAST_NAME_NN" NOT NULL )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_SALARY_MIN" CHECK (salary > 0) )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_MANAGER_FK" FOREIGN KEY ("MANAGER_ID") REFERENCES "HR"."EMPLOYEES" ("EMPLOYEE_ID") )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_DEPT_FK" FOREIGN KEY ("DEPARTMENT_ID") REFERENCES "HR"."DEPARTMENTS" ("DEPARTMENT_ID") )

ALTER TABLE "HR"."EMPLOYEES" ADD (CONSTRAINT "EMP_JOB_FK" FOREIGN KEY ("JOB_ID") REFERENCES "HR"."JOBS" ("JOB_ID") )

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿ ¿:

CREATE OR REPLACE procedure "HR".MGMT$MASK_GRANT_44 AS

grant_cur INTEGER;

BEGIN

grant_cur := DBMS_SQL.OPEN_CURSOR;

DBMS_SQL.PARSE (grant_cur, ' GRANT REFERENCES ON "HR"."EMPLOYEES" TO

"OE"', DBMS_SQL.NATIVE);

DBMS_SQL.CLOSE_CURSOR (grant_cur);

END;

BEGIN "HR".MGMT$MASK_GRANT_44; END;

DROP procedure "HR".MGMT$MASK_GRANT_44

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿ ¿:

CREATE OR REPLACE procedure "HR".MGMT$MASK_GRANT_44 AS

grant_cur INTEGER;

BEGIN

grant_cur := DBMS_SQL.OPEN_CURSOR;

DBMS_SQL.PARSE (grant_cur, ' GRANT SELECT ON "HR"."EMPLOYEES" TO "OE

"', DBMS_SQL.NATIVE);

DBMS_SQL.CLOSE_CURSOR (grant_cur);

END;

BEGIN "HR".MGMT$MASK_GRANT_44; END;

DROP procedure "HR".MGMT$MASK_GRANT_44

COMMENT ON COLUMN "HR"."EMPLOYEES"."COMMISSION_PCT" IS 'Commission percentage of the employee; Only employees in sales

department elgible for commission percentage'

COMMENT ON COLUMN "HR"."EMPLOYEES"."DEPARTMENT_ID" IS 'Department id where employee works; foreign key to department_id

column of the departments table'

COMMENT ON COLUMN "HR"."EMPLOYEES"."EMAIL" IS 'Email id of the employee'

COMMENT ON COLUMN "HR"."EMPLOYEES"."EMPLOYEE_ID" IS 'Primary key of employees table.'

COMMENT ON COLUMN "HR"."EMPLOYEES"."FIRST_NAME" IS 'First name of the employee. A not null column.'

COMMENT ON COLUMN "HR"."EMPLOYEES"."HIRE_DATE" IS 'Date when the employee started on this job. A not null column.'

COMMENT ON COLUMN "HR"."EMPLOYEES"."JOB_ID" IS 'Current job of the employee; foreign key to job_id column of the

jobs table. A not null column.'

COMMENT ON COLUMN "HR"."EMPLOYEES"."LAST_NAME" IS 'Last name of the employee. A not null column.'

COMMENT ON COLUMN "HR"."EMPLOYEES"."MANAGER_ID" IS 'Manager id of the employee; has same domain as manager_id in

departments table. Foreign key to employee_id column of employees table.

(useful for reflexive joins and CONNECT BY query)'

COMMENT ON COLUMN "HR"."EMPLOYEES"."PHONE_NUMBER" IS 'Phone number of the employee; includes country code and area code'

COMMENT ON COLUMN "HR"."EMPLOYEES"."SALARY" IS 'Monthly salary of the employee. Must be greater

than zero (enforced by constraint emp_salary_min)'

COMMENT ON TABLE "HR"."EMPLOYEES" IS 'employees table. Contains 107 rows. References with departments,

jobs, job_history tables. Contains a self reference.'

BEGIN DBMS_STATS.GATHER_TABLE_STATS('"HR"', '"EMPLOYEES"', estimate_percent=>DBMS_STATS.AUTO_SAMPLE_SIZE, degree=>DBMS_STATS.DEFAULT_DEGREE, cascade=>TRUE); END;

¿¿¿ ¿¿¿¿ ¿¿¿¿¿¿¿. ¿¿ ¿¿¿ ¿¿¿¿¿.

¿¿ ¿¿¿ ¿¿¿ ¿¿ ¿

¿¿ ¿¿¿ ¿¿¿¿ ¿¿¿

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿

¿¿¿ ¿¿¿¿ ¿¿¿¿ ¿¿¿

¿¿¿¿ ¿¿ ¿¿

SQL> set ver on

   

=================================================

   

3-2 중복 값이 있는 Data Masking

   

  • Data Masking 대상 컬럼(EMAIL) : Unique Index

   

   

  • 현재 Data 상태 확인

   

   

   

  • Data Masking 옵션 선택(부분 문자열): 4번째 칸까지의 데이터 출력

       

  • Data Masking 후 변경된 내용

       

   

   

  • 상태확인
    • 부분 Masking이 되면서 중복된 값이 발생되어 Unique Index를 생성하지 못하고 해당 데이터 변경만 이루어졌음.
    • 아래 실행 스크립트 로그를 확인하게 되면 해당 에러가 발생하면서 Index및 Constraints가 깨지는 것을 확인 할 수 있습니다.

         

   

   

   

<수행 스크립트 확인>

-- ¿¿ ¿¿¿¿¿¿: test

-- ¿¿¿¿ ¿¿ ¿¿: 03-9¿ -2012 13:48

¿¿¿ ¿¿¿ ¿¿ ¿

User is "SYS"

COMMIT

ALTER SESSION ENABLE PARALLEL DML

DROP TABLE "MGMT_DM_TT_21" PURGE

¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿¿, ¿¿ ¿¿ ¿

declare

adj number:=0;

num number:=0;

begin

select length(count(*)) into adj from (select distinct "EMAIL" from "HR"."EMPLOYEES");

num := adj;

adj := greatest(adj - 3, 0);

execute immediate 'create table MGMT_DM_TT_21

(orig

_val null, new_val null) NOLOGGING PARALLEL as

select CAST(null AS VARCHAR2(25)) orig_val, CAST(null AS VARCHAR2(25)) new_val from dual union all

select s.orig_val,

case

when s.subset = 1 then

CAST(

substr(s.orig_va

l, 4, 4)

AS VARCHAR2(25))

end new_val

from (select rownum rn, orig_val, subset, rid, lpad(rownum - 1, '||num||', 0) new_num

from (select "EMAIL" orig_val, min(rowid) rid, min(

case

when 1=1 then 1

 

end

) subset

from "HR"."EMPLOYEES" group by "EMAIL")) s

where 1=1 and s.orig_val is not null

';

DBMS_STATS.GATHER_TABLE_STATS(NULL, '"MGMT_DM_TT_21"', estimate_percent=>DBMS_STATS.AUTO_SAMPLE_SIZE, degree=>DBMS_STATS.DEFAULT_DEGREE);

end;

DROP TRIGGER "HR"."UPDATE_JOB_HISTORY"

DROP TRIGGER "HR"."SECURE_EMPLOYEES"

DECLARE

CURSOR fk_sql IS select refr.owner, refr.table_name, refr.constraint_name

from dba_constraints refd, dba_constraints refr

where refd.owner = 'HR' and

refd.table_name = 'EMPLOYEES' and

refr.constraint_ty

pe = 'R' and

refr.r_owner = refd.owner and

refr.r_constraint_name = refd.constraint_name;

BEGIN

FOR fk IN fk_sql

LOOP

EXECUTE IMMEDIATE 'ALTER TABLE "' || fk.owner || '"."' ||

fk.table_name || '" DROP CONSTRAINT "

' || fk.constraint_name || '"';

END LOOP;

END;

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿ ¿:

CREATE OR REPLACE procedure "HR".MGMT$MASK_GRANT_20 AS

grant_cur INTEGER;

BEGIN

grant_cur := DBMS_SQL.OPEN_CURSOR;

DBMS_SQL.PARSE (grant_cur, ' REVOKE REFERENCES ON "HR"."EMPLOYEES" F

ROM "OE"', DBMS_SQL.NATIVE);

DBMS_SQL.CLOSE_CURSOR (grant_cur);

END;

BEGIN "HR".MGMT$MASK_GRANT_20; END;

DROP procedure "HR".MGMT$MASK_GRANT_20

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿¿ ¿¿ ¿¿ ¿:

CREATE OR REPLACE procedure "HR".MGMT$MASK_GRANT_20 AS

grant_cur INTEGER;

BEGIN

grant_cur := DBMS_SQL.OPEN_CURSOR;

DBMS_SQL.PARSE (grant_cur, ' REVOKE SELECT ON "HR"."EMPLOYEES" FROM

"OE"', DBMS_SQL.NATIVE);

DBMS_SQL.CLOSE_CURSOR (grant_cur);

END;

BEGIN "HR".MGMT$MASK_GRANT_20; END;

DROP procedure "HR".MGMT$MASK_GRANT_20

DECLARE

CURSOR c_sql IS select owner, table_name, constraint_name,

constraint_type, generated, index_name from dba_constraints

where owner = 'HR' and

table_name = 'EMPLOYEES' and

constraint_type <> 'R';

BEGIN

FOR c I

N c_sql

LOOP

EXECUTE IMMEDIATE 'ALTER TABLE "' || c.owner || '"."' ||

c.table_name || '" DROP CONSTRAINT "' || c.constraint_name || '"';

END LOOP;

END;

DROP INDEX "HR"."EMP_DEPARTMENT_IX"

DROP INDEX "HR"."EMP_EMAIL_UK"

DROP INDEX "HR"."EMP_EMP_ID_PK"

DROP INDEX "HR"."EMP_JOB_IX"

DROP INDEX "HR"."EMP_MANAGER_IX"

DROP INDEX "HR"."EMP_NAME_IX"

ALTER TABLE "HR"."EMPLOYEES" RENAME TO "EMPLOYEES$DMASK"

CREATE TABLE "HR"."EMPLOYEES" TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 1 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING NOCOMPRESS PARALLEL AS SELECT s."EMPLOYEE_ID", s."FIRST_NAME", s."LAST_NAME", c0m21.NEW_VAL "EMAIL", s."PHONE_

NUMBER", s."HIRE_DATE", s."JOB_ID", s."SALARY", s."COMMISSION_PCT", s."MANAGER_ID", s."DEPARTMENT_ID" FROM "HR"."EMPLOYEES$DMASK" s , MGMT_DM_TT_21 c0m21 WHERE sys_op_map_nonnull(s."EMAIL") = sys_op_map_nonnull(c0m21.ORIG_VAL)

ALTER TABLE "HR"."EMPLOYEES" NOPARALLEL

DROP TABLE "HR"."EMPLOYEES$DMASK" PURGE

CREATE INDEX "HR"."EMP_DEPARTMENT_IX" ON "HR"."EMPLOYEES" ("DEPARTMENT_ID") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

CREATE UNIQUE INDEX "HR"."EMP_EMAIL_UK" ON "HR"."EMPLOYEES" ("EMAIL") TABLESPACE "EXAMPLE" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING

¿¿¿ ¿¿¿¿ ¿ ¿¿ ¿¿

ORA-01452:

ORA-01452: cannot CREATE UNIQUE INDEX; duplicate keys found

errorExitOraError!

¿¿¿ ¿¿¿¿ ¿¿¿¿¿¿¿. ¿¿ ¿¿¿ ¿¿¿¿¿.

¿¿¿ ¿¿¿¿ ¿¿¿ ¿¿ ¿

¿¿¿ ¿¿¿¿ ¿¿¿¿ ¿¿¿

¿¿¿¿ ¿¿ ¿¿

SQL> set ver on

   

   

결론

  • DATA Masking 시에 적용하는 옵션에 따라서 변경되는 데이터의 열에 중복되는 값이 있느냐, 없느냐에 따라서 Unique index를 포함하고 있는 대상 컬럼일 경우, 다른 곳의 컬럼에 있는 index 및 Constraints까지도 재생성 하지 못하게 되는 것을 확인할 수 있습니다.

   

  • Data Masking 시에 특히 Unique index를 포함하고 있는 컬럼의 경우, 중복된 데이터 값이 나오지 않도록 Masking 옵션을 신중하게 선택하여 적용할 필요가 있을 것으로 판단됩니다.

     

   

블로그 이미지

운명을바꾸는자

IT와 함께 살아가는 삶

,