EditPlus Macro 활용

2. Knowledge 2015. 7. 30. 21:49


Editplus Macro 활용

1.Macro 사용자 설정

  • Editplus의 Macro는 기록 시작부터 사용자가 키보드로 입력한 내역을 기억하여 저장하며 반복적인 문서 작업을 할 경우에 유리하다.

       

1) 도구 > 기록 tab

   

  • 키 입력을 저장해둘 번호를 선택한다.(저장된 내역은 언제든지 반복적으로 사용할 수 있다.)
  • 해당 내역을 클릭하면 마우스에 테이프 모양이 추가적으로 생성된다.

       

  1. 기록이 시작된 시점부터 키보드로 입력되는 내역을 기억하기 때문에 내가 반복적으로 작업할 내역을 키보드로만 1번 기록하면 된다.

       

    예) Ctrl+q 매크로 시작 => HOME => Ctrl+-> => shift+HOME => 제거 또는 입력 => 아래로 화살표 => Ctrl+q(매크로 완료) 동작 방법 alt+숫자 ( ctrl+f를 이용하여 원하는 조건의 데이터만 조작할 수 있음)

       

  • 키보드 단축키를 적절하게 활용하면 반복적인 문서작업을 할 경우에 편리함을 준다.

       

3) 기록이 끝나면 다시 "키 입력 기록"을 눌러주면 된다.

 

   

4) 기록된 내역을 수행하려면 Alt+1 (해당 하는 번호)의 단축키를 통하여 텍스트 수정에 적용할 수 있다.

   

2.Macro 반복 수행

1) 기록된 내역을 반복적으로 수행하고자 할 경우에 "반복 재생"을 활용하면 된다.

2) 기록된 번호를 선택한다.

   

3) 반복하고자 하는 횟수를 선택한다.

블로그 이미지

운명을바꾸는자

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와 함께 살아가는 삶

,



1.EM을 이용한 Oracle SQL Performance Analyzer

   

  • TEST환경 11.2.0.3 (SID=test) / 11.2.0.3 (SID=orcl) - 성공,
  • 11.2.0.3(SID=test) 9.2.0.8(SID=orcl) - 실패
  • Hr 유저에게 dba 권한을 부여하여 TEST진행.

       

2.문제가 되었던 오라클 패키지

  • SYS.DBMS_ADVISOR

    SYS>cd {ORACLE_HOME}/rdbms/admin/@dbmsadv.sql

       

  • SYS.DBMS_SQLPA

    SYS>cd {ORACLE_HOME}/rdbms/admin/dbmsspa.sql

       

    -해당 패키지가 존재 해야 된다. 10.2.0.4부터 DBMS_SQLPA가 존재하는 것으로 예상 됨.

 

  • 9i 같은 경우 위의 해당 DBMS 패키지가 존재하지 않아서 EM으로 동작할 경우 해당 패키지에러가 발생합니다 그래서 일단은 SPA의 전반적인 과정을 확인해 보기 위해서 두 개의 11G TEST 서버에서 진행 하였습니다.

       

   

  • EM에서 로그인하게 되면 성능 TAB에서 해당 SQL문 검색 및 튜닝집합 생성 후, SQL 성능분석기를 통하여 2개의 DB에 각각 SQL문을 돌린 실행계획을 확인할 수 있습니다.

       


       

3.SQL 검색을 통하여 해당 쿼리문을 추출하여 SQL튜닝 집합을 만듭니다.

  • 데이터 소스 및 필터 조건을 조절하여, 해당 쿼리문을 검색한합니다.
  • 검색 후, SQL 튜닝 집합에 저장 부분에서 새 SQL튜닝 집합 이름지정 후 저장합니다.

     

   

   

4.SQL 튜닝 집합 확인

  • SQL 튜닝 집합으로 만들어진 해당 이름과 스키마 쿼리문을 확인할 수 있다.

       

   

   

5.SQL 성능 분석기(SQL Performance Analyzer)

  • 다양한 형태의 성능 분석 방법들이 준비되어 있습니다.
  • 대략적인 TEST 순서는 아래와 같습니다.
    • 환경설정
    • SQL 튜닝 집합에 준하는 SQL Performance Analyzer 작업생성
    • 초기 환경에서 SQL Tuning Set 재생
    • 변경된 환경에서 SQL Tuning Set 재생(DB link를 이용하여 원격 DB에 접속)
    • 단계 2와 단계 3비교
    • 비교 보고서 보기

         

         

     

  • 여러가지 형식 중하나인 안내식 워크플로우를 보게 되면 단계별로 SQL 성능 분석기를 TEST할 수 있습니다.

       

   

  • TEST 완료 후 각 서버에서 SQL을 실행하여 얻은 결과보고서를 한눈에 볼 수 있습니다.
  • 아래쪽 비교 보고서를 보게 되면 SQL set으로 만들어 놓았던 쿼리문들에 대해서 자세하게 비교하여 볼 수 있습니다.

       

   

   

  • 하나의 쿼리문에 대하여 수집된 실행 계획을 확인할 수 있습니다.

       

   

  • 다른 옵션의 창인데, 수행 과정은 위와 동일하게 진행됩니다.

       

   

   

   

4.9.2.0.8i와 11.2.0.3를 가지고 위와 동일한 TEST를 하였지만 실패.

  • 그 원인 중에 하나는 9i에서는 oracle DBMS 패키지 중에 SYS.DBMS_ADVISOR, SYS.DBMS_SQLPA가 존재하지 않아서 스크립트가 돌아갈 때 아래와 같은 에러가 발생합니다.

       

  • 그래서 해당 패키지를 11G에서 설치 SQL문을 가지고 와서 패키지를 생성해 보았지만, 버전 차이로 인한 새로운 기능이라 추가적으로 다른 패키지 부족에러가 발생하였습니다.

       

  • EM만으로는 9i->11g test는 할 수 없고, 스크립트를 이용하여 진행할 경우 가능할 것으로 예상됩니다.

https://support.oracle.com/epmos/faces/ui/km/DocumentDisplay.jspx?_afrLoop=415397735012079&id=560977.1&_afrWindowMode=0&_adf.ctrl-state=y509e7up1_40

   

   

ORA-06512: "SYS.PRVT_ADVISOR", 2735행 ORA-06512: "SYS.DBMS_ADVISOR", 241행 ORA-06512: "SYS.DBMS_SQLPA", 342행 ORA-06512: "SYS.DBMS_SQLPA", 359행 ORA-06512: 1행

  

   

   

   

<참고문서>

https://support.oracle.com/epmos/faces/ui/km/DocumentDisplay.jspx?_afrLoop=415397735012079&id=560977.1&_afrWindowMode=0&_adf.ctrl-state=y509e7up1_40

   

http://docs.oracle.com/cd/E14072_01/server.112/e10822/tdppt_sqltune.htm#TDPPT160

   

https://support.oracle.com/epmos/faces/ui/km/DocumentDisplay.jspx?_afrLoop=403659916853090&id=562899.1&_afrWindowMode=0&_adf.ctrl-state=7b5uqhddb_177

   

https://support.oracle.com/epmos/faces/ui/km/DocumentDisplay.jspx?_afrLoop=403933301039403&id=742644.1&_afrWindowMode=0&_adf.ctrl-state=7b5uqhddb_186

블로그 이미지

운명을바꾸는자

IT와 함께 살아가는 삶

,

 

1.ADG DGMGRL

  • Data Guard 를 관리하기 위한 CLI (command line interface) 이다.

    수동으로 관리하게 되면 장애시점에서 수동으로 Primary, standby를 바꿔줘야 하지만 한번 설정하게 되면 자동으로 관리를 해주는 controller입니다.

       

2.DGMGRL 접속 및 명령어

localhost@orcl : /home/oracle> dgmgrl sys/oracle

DGMGRL for Linux: Version 11.2.0.3.0 - Production

   

Copyright (c) 2000, 2009, Oracle. All rights reserved.

   

Welcome to DGMGRL, type "help" for information.

Connected.

DGMGRL>

DGMGRL>

DGMGRL> help

   

The following commands are available:

   

add Adds a standby database to the broker configuration

connect Connects to an Oracle database instance

convert Converts a database from one type to another

create Creates a broker configuration

disable Disables a configuration, a database, or fast-start failover

edit Edits a configuration, database, or instance

enable Enables a configuration, a database, or fast-start failover

exit Exits the program

failover Changes a standby database to be the primary database

help Displays description and syntax for a command

quit Exits the program

reinstate Changes a database marked for reinstatement into a viable standby

rem Comment to be ignored by DGMGRL

remove Removes a configuration, database, or instance

show Displays information about a configuration, database, or instance

shutdown Shuts down a currently running Oracle database instance

sql Executes a SQL statement

start Starts the fast-start failover observer

startup Starts an Oracle database instance

stop Stops the fast-start failover observer

switchover Switches roles between a primary and standby database

   

Use "help <command>" to see syntax for individual commands

   

DGMGRL>

   

   

3.DGMGRL Configuration 생성

[Primary DB]

   

ocp@orcl : /home/oracle> dgmgrl sys/oracle

DGMGRL for Linux: Version 11.2.0.3.0 - Production

   

Copyright (c) 2000, 2009, Oracle. All rights reserved.

   

Welcome to DGMGRL, type "help" for information.

Connected.

   

DGMGRL>

create configuration 'test_DG' as

primary database is 'orcl'

connect identifier is 'orcl';

   

Error:

ORA-16525: the Data Guard broker is not yet available

ORA-06512: at "SYS.DBMS_DRS", line 157

ORA-06512: at line 1

   

[해결방안]

Database dg_broker_start 모두 false이므로 위와 같은 Error 발생함.

Primary, standby 모두 true 변경(DG Broker start)

Alter system set dg_broker_start=true;

   

DGMGRL> show configuration;

   

Configuration - test_DG

   

Protection Mode: MaxPerformance

Databases:

orcl - Primary database

   

Fast-Start Failover: DISABLED

   

Configuration Status:

DISABLED

   

  

[Primary DB] - standby DB 추가

   

DGMGRL>

add database 'stby' as

connect identifier is 'stby';

   

Database "stby" added

   

   

DGMGRL> show configuration;

   

Configuration - test_DG

   

Protection Mode: MaxPerformance

Databases:

orcl - Primary database

stby - Physical standby database

   

Fast-Start Failover: DISABLED

   

Configuration Status:

DISABLED

   

DGMGRL> enable configuration;

Enabled.

   

DGMGRL> show configuration;

   

Configuration - test_DG

   

Protection Mode: MaxPerformance

Databases:

orcl- Primary database

stby- Physical standby database

   

Fast-Start Failover: DISABLED

   

Configuration Status:

SUCCESS

  

   

   

4.DGMGRL Switch Over

  • 장애가 발생할 경우 Primary DB-> standby DB Switch Over 기능

DGMGRL> switchover to stby;

Performing switchover NOW, please wait...

New primary database "stby" is opening...

Operation requires shutdown of instance "orcl" on database "orcl"

Shutting down instance "orcl"...

ORACLE instance shut down.

Operation requires startup of instance "orcl" on database "orcl"

Starting instance "orcl"...

ORACLE instance started.

Database mounted.

Database opened.

Switchover succeeded, new primary is "stby"

   

   

[참고문헌]

http://h391106.tistory.com/231

http://docs.oracle.com/cd/B19306_01/server.102/b14239/concepts.htm

http://h391106.tistory.com/238

http://download.oracle.com/docs/cd/E11882_01/server.112/e17023/dgmgrl.htm

   

블로그 이미지

운명을바꾸는자

IT와 함께 살아가는 삶

,