블로그 이미지
redkite

카테고리

분류 전체보기 (291)
00.SI프로젝트 산출물 (0)
00.센터 운영 문서 (0)
01.DBMS ============.. (0)
01.오라클 (117)
01.MS-SQL (15)
01.MySQL (30)
01.PostgreSql (0)
01.DB튜닝 (28)
====================.. (0)
02.SERVER ==========.. (0)
02.서버-공통 (11)
02.서버-Linux (58)
02.서버-Unix (12)
02.서버-Windows (2)
====================.. (0)
03.APPLICATION =====.. (11)
====================.. (0)
04.ETC =============.. (0)
04.보안 (5)
====================.. (0)
05.개인자료 (1)
06.캠핑관련 (0)
07.OA관련 (1)
Total
Today
Yesterday

달력

« » 2024.5
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

공지사항

최근에 올라온 글

ALTER PROFILE "DEFAULT" LIMIT
SESSIONS_PER_USER UNLIMITED
CPU_PER_SESSION UNLIMITED
CPU_PER_CALL UNLIMITED
CONNECT_TIME UNLIMITED
IDLE_TIME UNLIMITED
LOGICAL_READS_PER_SESSION UNLIMITED
LOGICAL_READS_PER_CALL UNLIMITED
COMPOSITE_LIMIT UNLIMITED
PRIVATE_SGA UNLIMITED
FAILED_LOGIN_ATTEMPTS 10
PASSWORD_LIFE_TIME UNLIMITED
PASSWORD_REUSE_TIME UNLIMITED
PASSWORD_REUSE_MAX UNLIMITED
PASSWORD_LOCK_TIME UNLIMITED
PASSWORD_GRACE_TIME UNLIMITED
PASSWORD_VERIFY_FUNCTION NULL;

비밀번호 관리

암호관리란?

더 뛰어난 데이터베이스 보안을 위해서 관리자가 프로파일로 오라클 암호를 관리 제어 할 수 있는 기능을 말합니다.

암호관리의 기능

- 계정 잠금(Accont locking) : 계정잠금 이란 사용자가 지정된 시도 횟수 내에 시스템에 로그인하지 못한 경우 자동적으로 계정을 잠그는 기능을 말합니다.

- 암호의 노화(aging)와 기간 만료(expire) : 암호가 수명을 갖도록 하여 그 기간이 지나면 암호를 변경 하도록 설정하는 기능 입니다.

- 암호의 현재까지의 기록(Password history) : 암호를 검사하여 지정된 시간 동안이나 지정된 횟수 이상 사용되지 않도록 설정 할 수 있습니다.

- 암호의 복잡성 검증(Password complexity verification) : 추측된 암호를 사용하지 못하도록 암호를 충분히 복잡하게 설정 할 수 있는 기능 입니다.

암호관리를 사용하는 방법

- 프로파일을 사용자에게 지정하여 암호관리를 설정 합니다.

- CREATE USER나 ALTER USER 명령을 사용하여 계정을 잠그거나 잠금을 해제하고 기간을 만료 할 수 있습니다.

- 인스턴스의 RESOURCE_LIMIT가 FALSE로 설정되어 있더라도 암호제한은 항상 시행 됩니다.

- 자원 제한 설정과 비슷하게 CREATE나 ALTER USER 명령을 사용하여 암호 설정을 제한하도록 프로파일을 생성하여 사용자에게 지정할 수 있습니다.

- SESSIONS_PER_USER 같은 다른 제한들은 초기화 파라미터나 ALTER SYSTEM 명령으로 자원 제한이 enable되어 있을 때에만 시행되는 반면, 프로파일의 암호 설정은 항상 시행 됩니다.

- 암호 관리가 enable되면 사용자 계정은 CREATE USER나 ALTER USER 명령을 사용하여 잠그거나 잠금을 해제할 수 있습니다.

암호 설정 방법

아래와 같이 프로파일을 생성 하고 그 프로파일을 암호설정을 적용할 유저에게 부여하면 됩니다.

 

SQL> CREATE PROFILE scott_password

LIMIT FAILED_LOGIN_ATTEMPTS 3 ---> 로그인 실패 횟수

PASSWORD_LIFE_TIME 30 ---> 기간만료일

PASSWORD_REUSE_TIME 30 ---> 암호가 재사용 될 때까지의 날 수

PASSWORD_VERIFY_FUNCTION verify_function ---> 복합성 검사를 수행할 PL/SQL

PASSWORD_GRACE_TIME 5 ; ---> 유예기간

 

암호 설정 관련 파라미터

Parameter

설 명

FAILED_LOGIN_ATTEMPTS
[계정잠금]

계정을 잠그기 전까지 로그인 시도하다 실패한 횟수.

오라클 서버는 FAILED_LOGIN_ATTEMPTS 값에 도달하면 자동적으로 계정을 잠근다.

계정은 지정된 시간(PASSWORD_LOCK_TIME)이 지난 후 자동적으로 잠금이 해제되거나 데이터베이스 관리자가 ALTER USER 명령으로 잠금을 해제해야 한다.

데이터베이스 계정은 ALTER USER 명령을 사용하여 명시적으로 잠글수도 있는데 이렇게 하면 계정은 자동적으로 잠금 해제되지 않는다

PASSWORD_LOCK_TIME
[계정잠금]

암호가 기간 만료되어 계정이 잠겨진 채로 남아 있었던 날 수

PASSWORD_LIFE_TIME
[노화와 기간만료]

날 수로 표시한 암호의 수명으로 이 기간이 지나면 기간 만료됨

PASSWORD_GRACE_TIME
[노화와 기간만료]

암호가 기간 만료된 후 첫번째 성공적인 로그인부터 암호 변경을 할 때까지의 유예기간

PASSWORD_REUSE_TIME
[현재까지의 기록]

암호가 재사용 될 때까지의 날 수

PASSWORD_REUSE_MAX
[현재까지의 기록]

암호가 재사용 될 수 있는 최대 회수

PASSWORD_VERIFY_FUNCTION
[복합성 검증]

암호를 할당 하기 전 복합성 검사를 수행할 PL/SQL 함수

암호 노화(Aging) 기간 만료

- PASSWORD_LIFE_TIME 파라미터는 패스워드의 수명을 설정 합니다. 이 기간이 지나면 암호를 변경해야 합니다.

- 데이터베이스 관리자는 유예 기간(PASSWORD_GRACE_TIME)을 지정할 수 있습니다. 이 기간은 암호가 기간 만료된 후 데이터베이스에 처음 접속한 때부터 시작 됩니다.

- 유예 기간이 끝날 때까지는 사용자가 매번 접속하려 할 때마다 경고 메시지가 발생 하며, 사용자는 유예 기간 내에 암호를 변경해야 합니다. 암호가 변경되지 않으면 계정은 잠깁니다.

- 암호를 기간 만료된 것으로 명시적으로 설정하면 사용자의 계정 상태는 EXPIRED로 변경됩니다. 이렇게 되면, 사용자가 로그인 할 때 계정은 유예 기간으로 넘어 갑니다.

암호의 현재까지의 기록

- 암호의 현재까지의 기록은 사용자가 지정된 기간 동안 암호를 재사용하지 못하게 합니다. 아래의 한 가지 방법으로 구현할 수 있습니다.

- PASSWORD_REUSE_TIME : 주어진 날 수 동안 암호를 재사용할 수 없도록 지정.

- PASSWORD_REUSE_MAX : 예전에 사용한 암호와 동일한 것을 사용하지 못하도록 시행.

Password Verification Function VERIFY_FUNCTION

- 사용자에게 암호를 할당하기 전에 암호의 유효성을 검증 할 수 있습니다.

- 암호의 최소길이는 네문자 입니다.

- 암호는 사용자 이름과 같아서는 안된다.

- 암호는 최소한 하나의 알파벳,하나의 수자,그리고 하나의 특수 문자를 가져야한다.

- 암호는 예전에 사용했던 암호와 최소한 세문자는 달라야한다.

- utlpwdmg.sql 스크립트에 의해 VERIFY_FUNCTION이라는 디폴트 PL/SQL 함수 형태로 제공되며 반드시 SYS 스키마에서 실행되어야 합니다.

- 디폴트 profile의 PASSWORD_VERIFY_FUNCTION 기능을 사용하지 않으려면 아래의 명령어를 실행하면 됩니다.

 

SQL> ALTER PROFILE DEFAULT LIMIT PASSWORD_VERIFY_FUNCTION NULL;

 

계정 잠금과 암호 제어(Controlling Account Lock and Password)

ALTER USER 명령을 사용하여 암호를 변경하고 계정을 잠글 수 있습니다. 이와 같은 작업이 필요한 경우는 다음과 같습니다.

  • - 사용자가 암호를 잃어버려서 암호를 재설정하고자 할 때
  • - 시스템에 의해 잠겨진 사용자 계정을 풀 때
  • - 계정을 명시적으로 잠글 때
  • - 수동으로 암호를 만료되게 할 때, 사용자 암호를 재설정할 때 유용합니다.

암호 만료후 재설정 문법

 

ALTER USER user

[ IDENTIFIED {BY password | EXTERNALLY } ]

[ PASSWORD EXPIRE ]

[ ACCOUNT { LOCK | UNLOCK } ] ;

 

암호 만료후 재설정 예제

 

SQL> ALTER USER scott

IDENTIFIED BY puhaha

PASSWORD EXPIRE ;

 

사용자가 로그인한 상태라면 암호 변경, 만료, 잠금은 현재의 세션에는 영향을 주지 않습니다. 사용자 계정이 잠겨져 있는데 접속하려 하면 아래와 같은 메세지가 출력 됩니다

 

ERROR:

ORA-28000: the account is locked

Warning: You are no longer connected to ORACL

 

Posted by redkite
, |

### 컨트롤 파일 ####

   
   
   
   
  1. 컨트롤 파일 미러링
    1) spfile의 경우
    shutdown immediate; -- DB서버를 정지
    alter system set controlfiles = '/data/controlfile1.ctl', '/data/controlfile2.ctl' scope=spfile; -- 파일 추가
    cp /data/controlfile1.ctl /data/controlfile2.ctl ## OS에서 파일 복사
    startup
    2) pfile의 경우
    shutdown immediate; -- DB서버 정지
    vi /data/admin/pfileSID.ora 파일에 컨트롤 파일 추가
    cp /data/controlfile1.ctl /data/controlfile2.ctl ## OS에서 파일 복사
    startup

  1. 컨트롤 파일 복구
    SQL> select spid, name from v$process, v$bgprocess where paddr(+) = addr; -- 프로세스 확인
    SQL> show parameter user_dump_dest

    NAME TYPE VALUE
    ------------------------------------ ----------- ------------------------------
    user_dump_dest string /data/oracle/app/oracle/admin/emsdb/udump -- 해당 디렉토리에는 컨트롤 파일을 재생성할 수 있는 스크립트가 저장되어 있음.
    SQL > shutdown immediate;
    cd /data/oracle/app/oracle/admin/emsdb/udump/
    grep controlfile *.trc ## 해당 파일 찾은 후
    cp -p SID_ora_PID.trc controlfile.sql ## 파일 변경 후
    sqlplus "/as sysdba"
    SQL > @controlfile.sql -- 실행 하면 컨트롤 파일 및 아카이브 파일이 생성 된다. 일부 에러 발생 가능성 있음.

### 리두로그 파일 ###

  1. 리두 로그 파일 미러링
    SQL > select * from v$logfile; -- 로그 파일 확인
    SQL > select * from v$log; -- 현재 사용 중인 로그 파일 확인 및 MEMBERS 의 수가 1만 있을 경우 미러링이 안되어 있는 것임
    SQL > alter database add logfile group 2 '/data/redo/redolog2_1.log' size 500M; -- 그룹 생성
    SQL > alter database add logfile member '/data/redo/redolog2_2.log' to group 2; -- 2그룹에 대한 추가 파일 생성

### 아카이브 모드 확인 ###

SQL> archive log list
Database log mode Archive Mode
Automatic archival Enabled
Archive destination /data/archivelog
Oldest online log sequence 748
Next log sequence to archive 750
Current log sequence 750

SQL> archive log list
Database log mode Archive Mode
Automatic archival Enabled
Archive destination /data/archivelog
Oldest online log sequence 748
Next log sequence to archive 750
Current log sequence 750

SQL> select group#, sequence#, archived, status from v$log;

GROUP# SEQUENCE# ARC STATUS
---------- ---------- --- ----------------
1 748 YES INACTIVE
2 749 YES INACTIVE
3 750 NO CURRENT
4 595 YES INACTIVE
5 596 YES INACTIVE
6 597 NO CURRENT

6 rows selected.


SQL> select archiver from v$instance;

ARCHIVE
-------
STARTED


### 오프라인 백업(노아카이브 모드) ###

  1. 주의 할 점
    오프라인 백업 시에는 정상적인 방법으로 종료(normal, immediate, transactional) 해야 한다. abort 종료의 경우 메모리 상의 할당된 내용도 즉시 종료 하고 데이터 베이스를 종료하기 때문에 나중에 스타트업 시에 복구 작업을 수행하게 된다. 이때 수행하는 프로세스는 SMON이다.
  2. 백업 받을 파일은 컨트롤 파일, 데이터 파일, 리두로그 파일, 파라메터 파일 전부를 같은 시점에 백업 받아야 한다.
    한번에 같이 받지 않으면 복구 시점이 틀어지게 된다. 이유는 컨트롤 파일의 SCN 번호 부여가 바뀌기 때문이다.
  3. 백업 전 확인 사항
    SQL > select TABLESPACE_NAME, FILE_NAME from dba_data_files; -- 데이터 파일의 구조 분석
    SQL > select GROUP#, MEMBER from v$logfile; -- 리두로그 파일의 구조 분석
    SQL > select * from v$confile; -- 컨트롤 파일의 구조 분석
    SQL > host edit /data/oracle/products/pfile/initSID.ora -- 파라메터 파일 구조 분석

    ## 오라클 DB 정상적인지 확인SQL > host edit moredept.sql
    alter system switch logfile;
    insert into scott.dept values(1,'Personnen','Pusan');
    insert into scott.dept values(2,'Personnen','Pusan');
    insert into scott.dept values(3,'Personnen','Pusan');
    alter system switch logfile;
    insert into scott.dept values(4,'Personnen','Pusan');
    insert into scott.dept values(5,'Personnen','Pusan');
    insert into scott.dept values(6,'Personnen','Pusan');
    alter system switch logfile;
    insert into scott.dept values(7,'Personnen','Pusan');
    insert into scott.dept values(8,'Personnen','Pusan');
    insert into scott.dept values(9,'Personnen','Pusan');
    commit;
    select count(*) from scott.dept
    SQL > @moredept

  4. 특정 파일이 삭제되어 데이터 베이스 OPEN이 안될 경우
    startup -- 에러 발생될 경우 해당 파일을 아래의 명령어로 변경 후 open 시도 ## 컨트롤 파일의 파일경로 수정을 해주는 단계임.
    alter database rename file '/data/users01.dbf' to '/data/oradata/users01.dbf';
    alter database open;

### 아카이브 모드 백업-복구 ###

  1. 아카이브 모드 변경 작업
    1) initSID.ora 파일에 아래의 내용을 넣는다.
    LOG_ARCHIVE_START = TRUE
    LOG_ARCHIVE_DEST = [archivefile의 경로와 파일명]
    LOG_ARCHIVE_DEST_n = [archivefile의 경로와 파일명] ## DB_RECOVERY_FILE_DEST 파라메터를 정의하면 안된다.(해당 경로는 10g에서 플래시백에서 사용함)
    LOG_ARCHIVE_FORMAT = [format type].[확장자] ## sample [%r_%s.arc]
    ## [%s]아카이브의 일련번호 : 1, 2, 3 ... [%S] 아카이브 파일의 일련번호를 0으로 채워줌 00001, 00002, 00003 ...
    ## [%t]데이터 베이스의 인스턴스를 구분해서 표시해줌 [%T] 001, 002, 003...
    ## [%r]재시작된 후 아카이브 파일의 혼동을 줄이기 위해 RESETLOG ID 값을 구분하기 위한 것임.alter database open resetlogs명령어에 의해..(10g부터 적용됨)
    DB_RECOVERY_FILE_DEST ="
    2) 아카이브 모드 변경
    startup mount
    alter database archivelog;
    alter database open;
  2. 아카이브 모드 복구 절차(전체 복구 방법)
    1) FULL 백업 된 파일들의 백업 시점이 일치하는지 확인.
    2) 아카이브 모드로 운영중인지 확인.
    3) 최종 FULL 백업된 이후의 아카이브 로그 파일이 있는지 확인.
    4) 최종 리두로그 파일이 존재하는지 확인.(select * v$log;) -- 마운트 단계까지 들어간다.
    5) 장애가 발생한 데이터 파일 확인.(select * v$recover_file; select file_id, file_name from dba_data_files;) 에러가 발생한 DBF파일을 복사해 놓는다.
    6) 데이터 베이스 STARTUP
    7) recover database;
    8) auto
    9) alter database open
  3. 아카이브 모드 복구 절차(테이블 스페이스 완전 복구 방법)
    1) 오픈단계에서 장애발생 테이블스페이스 기준으로 복구한다.
    2) 오프라인 백업 데이터의 생성일자를 확인한다.
    3) 아카이브 모드로 운영중인지의 여부 확인한다.
    4) DB shutdown 후에 해당 테이블 스페이스의 데이터 파일을 복사한다.
    5) DB startup 한다. 기동 시에 해당 데이터 파일의 시점 불일치 에러 메시지가 발생한다.(ORA-01113, ORA-01110)
    6) alter database datafle 'OOOO.DBF' offline ;
    7) ALTER DATABASE OPEN; -- 을 실행하여 정상적으로 OPEN 시도.
    8) ALTER TABLESPACE OOOO OFFLINE IMMEDIATE; -- 해당 테이블 스페이스는 ONLINE상태로 OFFLINE으로 변경해줘야 한다.
    9) RECOVER TABLESPACE OOOO;
  4. 아카이브 모드 복구 절차(데이터파일 완전 복구 방법)
    1) 오픈단계에서 장애발생 데이터 파일기준으로 복구한다.
    2) 오프라인 백업 데이터의 생성일자를 확인한다.
    3) 아카이브 모드로 운영중인지의 여부 확인한다.
    4) DB shutdown 후에 해당 데이터 파일을 복사한다.
    5) DB startup 한다. 기동 시에 해당 데이터 파일의 시점 불일치 에러 메시지가 발생한다.(ORA-01113, ORA-01110)
    6) alter database datafle 'OOOO.DBF' offline IMMEDIATE;
    7) ALTER DATABASE OPEN; -- 을 실행하여 정상적으로 OPEN 시도.
    8) RECOVER DATAFILE 'OOOO.DBF';
    9) AUTO
  5. 아카이브 모드 복구 절차(read-only 테이블 복구)
    1) 백업 파일 복사
    2) startup mount -- DB를 마운트 단계까지 간다.
    3) recover database
    4) alter database open;
    5) alter tablespace TABLESPACE_NAME read only;
  6. 패러럴 복구 절차

    1) initSID.ora 파일 관련 파라메터 수정(Parallel_min_servers=2 / Parallel_max_servers=4 / Recovery_parallel_servers =4)
    2) select name from v$bgprocess; (P000, P001 등 프로세스가 수행됨)
    3) recover database parallel(degree 4)

  7. 시간기반 불완전 복구 방법
    1) DROP 된 테이블을 DROP 시키기 전으로 복구
    2) 로그마이너 패키지로 확인 가능



    3) 백업된 모든 데이터 파일 복사
    ** 주의 **
    장애가 발생한 데이터 파일만 복사하여 아카이브 파일들을 순차적으로 적용하게 되면 복구 작업이 완료되었지만, 불완전 복구 방법에서는
    특정 파일만 재 설치해서는 모든 데이터를 과거 특정시점으로 되돌릴 수 없기 때문에 반드시 모든 데이터를 과거 시점으로 복구 해야 함.
    불완전 복구 작업을 수행할 때 가장 중요한 포인트 중에 하나는 마지막 오프라인 백업된 모든 데이터 파일들을 현재
    경로로 복사 해야 한다는 것임.
    이때, 마지막 컨트롤 파일이나 리두로그 파일들은 복사할 필요는 없으며, 데이터 파일이 깨진 것이므로 모든 데이터 파일들만 복사 해야 함.
    4) STARTUP MOUNT
    5) SET AUTORECOVERY ON
    6) RECOVER DATABASE UNTIL TIME '2011-07-12-12:10:10'; ## 시점 복구
    7) ALTER DATABASE OPEN; ## 해당 명령을 실행하면 아래와 같은 에러 메시지 발생.
    ORA- Can not open Database; Please Open Database with resetlog option
    8) ALTER DATABASE OPEN RESETLOGS; ## SCN과 모든 로그 파일이 새로 시작되는 것임
    archivce log list 로 확인 가능
    9) DROP 된 테이블 복구 확인 후 OFF-LINE 백업 꼭 수행해야 함!!!(## RESETLOGS로 로그파일이 초기화 되기 때문에 꼭 백업 해야 함)
  8. 취소 기반 불완전 복구
    1) 복구 파일 복사 후 STARTUP MOUNT
    2) SET AUTORECOVERY ON
    3) RECOVER DATABASE UNTIL CANCEL; 과거 특정 시점까지 복구 완료
    ### 리두로그 파일 일부 삭제 시 복구

    ### 리두로그 파일 전체 삭제 시 복구



    ### 모든 컨트롤 파일이 삭제된 경우

    마지막 Current Redo log 파일을 지정해 주어야 함.
    ### 컨트롤 파일과 특정 datafile 삭제된 경우
  9. 변경기반 불완전 복구 방법
    1) RECOVER DATAABASE UNTIL CHANGE 80014;

6/2 일 SQL 튜닝 교육 5090912_workshop.zip5090914_labs.zip

  1. blocks 할당이 크고 avg_space의 크기가 크면 공간 낭비가 심한것임.
    SQL > select table_name, num_rows, blocks, avg_space, last_analyzed
    from user_tables
    where table_name like '%'
    SQL > save a1 -- 저장됨.
    SQL > get a1 -- 불러오기
    SQL > exec dbms_stats.gather_table_stats('sh','cust_test'); -- 통계정보 갱신
    SQL > exec dbms_stats.delete_table_stats('sh','sales_test'); -- 통계정보 삭제
  2. blevel 이 4level 로 떨어질 경우 공간 활용도가 떨어지고 있다는 것임.
    SQL > select index_name, num_rows, distinct_keys, leaf_blocks, blevel
    from user_indexes
    where table_name = 'sales_test'
  3. SQL TRACE
    SQL > alter session set tracefile_identifier = 'statement_trace';
    SQL > alter session set sql_trace=true;
    SQL > select max(cust_credit_limit) from customers
    where cust_city = ' Paris';
    SQL > alter session set sql_trace=false;
    #> tkprof orcl_ora_2364_statement_trace.trc run1.txt sys=no ## recursive SQL 문장 제외하라는 옵션(sys=no)
    SQL > create index cust_city_idx on customers(cust_city); -- index 생성 후 재실행해서 확인
  4. STATSPACK 생성 방법
    SQL > @%ORACLE_HOME%\rdbms\admin\spcreate
    perfstat_password의 값을 입력하십시오: pertstat
    pertstat


    Choose the Default tablespace for the PERFSTAT user
    ---------------------------------------------------
    Below is the list of online tablespaces in this database which can
    store user data. Specifying the SYSTEM tablespace for the user's
    default tablespace will result in the installation FAILING, as
    using SYSTEM for performance data is not supported.

    Choose the PERFSTAT users's default tablespace. This is the tablespac
    in which the STATSPACK tables and indexes will be created.

    TABLESPACE_NAME CONTENTS STATSPACK DEFAULT TABLESPACE
    ------------------------------ --------- ----------------------------
    EXAMPLE PERMANENT
    SYSAUX PERMANENT *
    USERS PERMANENT

    Pressing <return> will result in STATSPACK's recommended default
    tablespace (identified by *) being used.

    default_tablespace의 값을 입력하십시오: USERS

    Using tablespace USERS as PERFSTAT default tablespace.


    Choose the Temporary tablespace for the PERFSTAT user
    -----------------------------------------------------
    Below is the list of online tablespaces in this database which can
    store temporary data (e.g. for sort workareas). Specifying the SYSTEM
    tablespace for the user's temporary tablespace will result in the
    installation FAILING, as using SYSTEM for workareas is not supported.

    Choose the PERFSTAT user's Temporary tablespace.

    TABLESPACE_NAME CONTENTS DB DEFAULT TEMP TABLESPACE
    ------------------------------ --------- --------------------------
    TEMP TEMPORARY *

    Pressing <return> will result in the database's default Temporary
    tablespace (identified by *) being used.

    temporary_tablespace의 값을 입력하십시오: temp
    SQL > show user
    SQL > exec statspack.snap; -- 스냅샷 찍음.

  5. SQL Access Advisor TEST
    SQL > exec dbms_stats.gather_table_stats('sh','sales_test');
    SQL> select * from sales_test where cust_id = 100866;
    SQL> select * from sales_test1 where cust_id=100866;
    SQL> select c.cust_id, s.channel_id, sum(s.amount_sold)
    from customers c, sales s
    where c.cust_id = s.cust_id
    group by c.cust_id, s.channel_id
  6. Materialized View
    - JOIN하는 테이블들에 Mview 생성이 되면 summary 된 하나의 테이블 형식으로 조회가 되며, 사용자가 기존의 쿼리를 사용하여
    조회를 하더라도 Mview가 자동으로 자체 쿼리를 생성하여 응답속도를 빠르게 조회한다.
  7. leaf block 공간 낭비 확인
    SQL> select lf_rows_len, del_lf_rows_len, (del_lf_rows_len/lf_rows_len)*100 "Delete %" from index_stats
    SQL> update cust_test set cust_id=cust_id + 20000000
    where rownum <= 2000; -- 업데이트 후 확인작업
    SQL> analyze index cust_id_idx validate structure; -- 통계 정보 갱신 후 블럭 확인
    SQL> select lf_rows_len, del_lf_rows_len, (del_lf_rows_len/lf_rows_len)*100 "Delete %" from index_stats
    LF_ROWS_LEN DEL_LF_ROWS_LEN Delete %
    ----------- --------------- ----------
    911322 29881 3.27886301 <== %가 20% 이상이면 공간 활용도가 낮음으로 rebuild 필요함.

    1 개의 행이 선택되었습니다.
    SQL> alter index cust_id_idx rebuild;

  8. Unused Index 모니터링
    SQL> select 'alter index '||index_name||' monitoring usage;' from user_indexes;
    SQL> select table_name, index_name, monitoring, used from v$object_usage

    SQL> exec dbms_stats.gather_schema_stats('hr'); -- 통계정보 갱신 후 확인하게 되면 index가 사용된 걸로 확인된다.(안좋음ㅡㅡ;)

6/3일 SQL 튜닝 교육

  1. function based index
    SQL> create index func_first_name_idx on cust_test(upper(cust_first_name));
    SQL> select index_name, index_type, status from user_indexes
    where table_name = 'CUST_TEST';
    SQL> select index_name, column_name, column_position
    from user_ind_columns
    where table_name = 'CUST_TEST'
    order by 1, 3;
    SQL> select index_name, column_expression
    from user_ind_expressions
    where table_name = 'CUST_TEST';
  2. HINT
    - /*+ */ <== 힌트 포맷, 여러개의 힌트 사용시 한 포맷안에서 띄어쓰기로 작성.
  3. TRACE
    SQL> set autot traceonly explain
    SQL> select /*+ index(sales_test prod_time_idx) */ *
    from sales_test
    where prod_id=13
    and time_id between to_date('19980510', 'yyyymmdd')
    and to_date('19980522','yyyymmdd');
  4. Meterialized view
    SQL> create materialized view cust_sales_mv
    enable query rewrite
    as
    select c.cust_id, s.channel_id, sum(s.amount_sold)
    from customers c, sales s
    where c.cust_id = s.cust_id
    group by c.cust_id, s.channel_id;
    SQL> create materialized view cust_sales_mv1
    enable query rewrite
    as
    select c.cust_id, s.channel_id, sum(s.amount_sold)
    from customers c, sales s
    where c.cust_id = s.cust_id
    group by c.cust_id, s.channel_id;
    SQL> set autot traceonly explain
    SQL> alter materialized view cust_sales_mv disable query rewrite;
  5. Using DBMS_MVIEW Package
    declare
    task_nm varchar2(20) := 'emp_tune';
    begin
    dbms_advisor.tune_mview(task_name=>task_nm,
    mv_create_stmt=>'create materialized view emp_mv
    as
    select department_id, avg(salary)
    from employees
    group by department_id');
    end;
    /
  6. FLASHBACK
    - 9i 에서는 DML 에 대해 flashback query
    - 10g Database :

    . table --> Drop
    --> Table
    --> Version
    --> Transaction
    #### flashback transaction
    SQL> select to_char(sysdate, 'yyyy/mm/dd hh24:mi:ss') from dual;
    SQL> delete from dept where deptno=40;
    SQL> select * from dept as of timestamp
    to_timestamp('2011/06/03 15:46:07', 'yyyy/mm/dd hh24:mi:ss') -- 과거 특정 시간대로 돌아갈 경우
    where deptno=40 -- 과거 시간대 40번 부서가 있었는지 확인
    SQL> select * from dept as of timestamp
    systimestamp - interval '10' minute
    -- 과거 시간대로 돌아갈 경우
    where deptno=40 -- 과거 시간대 40번 부서가 있었는지 확인
    SQL> select * from dept as of timestamp
    sysdate - 10/1440
    -- 과거 시간대로 돌아갈 경우(10분/60분 환산 * 24)
    where deptno=40 -- 과거 시간대 40번 부서가 있었는지 확인
    SQL> show parameter undo
    undo_retention integer 900 -- 복구 가능한 최대 시간(900초)
    undo 공간이 부족할 경우 해당 과거 시간까지의 데이터를 보장 못함(젠장)
    SQL> show recyclebin -- 휴지통에서 확인(drop된 테이블 확인할 수 있음)
    ORIGINAL NAME RECYCLEBIN NAME OBJECT TYPE DROP TIME
    ---------------- ------------------------------ ------------ -------------------
    EMP_FLASH BIN$s/Vv2p9dSemiALQ05QJWuw==$0 TABLE 2011-06-03:16:09:14
    EMP_FLASH BIN$ahDZ8KZxQ2+26wiG+vjimA==$0 TABLE 2011-06-03:16:07:48
    EMP_FLASH BIN$aS6Q/kqETYa2NLqb7m+LHA==$0 TABLE 2011-06-03:16:06:36
    SQL> select * from "BIN$ahDZ8KZxQ2+26wiG+vjimA==$0"
    #### flashback drop
    SQL> flashback table emp_flash to before drop; -- drop 테이블 복원
    플래시백이 완료되었습니다.
    SQL> flashback table "BIN$aS6Q/kqETYa2NLqb7m+LHA==$0" to before drop; -- 특정 테이블 복구시
    플래시백이 완료되었습니다.
    SQL> flashback table "BIN$ahDZ8KZxQ2+26wiG+vjimA==$0" to before drop rename to emp_new; -- 테이블 이름을 변경 하여 복구도 가능
    플래시백이 완료되었습니다.
    #### flashback table
    16:24:37 SQL> insert into dept values(50,'New','CA');

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

    16:25:07 SQL> commit;

    커밋이 완료되었습니다.

    16:25:36 SQL> update dept set loc = 'Test1' where deptno=10;

    1 행이 갱신되었습니다.

    16:25:51 SQL> commit;

    커밋이 완료되었습니다.

    16:25:54 SQL> select * from dept;

    DEPTNO DNAME LOC
    ---------- -------------- -------------
    50 New CA
    10 ACCOUNTING Test1
    20 RESEARCH DALLAS
    30 SALES CHICAGO
    16:27:59 SQL> alter table dept enable row movement; -- 테이블의 row 이동 가능 활성화
    16:28:07 SQL> flashback table dept to timestamp to_timestamp('2011/06/03 16:24:37', 'yyyy/mm/dd hh24:mi:ss'); -- 테이블 자체 rollback
    플래시백이 완료되었습니다.

Posted by redkite
, |

Overview

오래전 메가존(현 혜택존) 서비스를 담당하던 시기, 포인트 관련된 부분에서 심각한 성능 저하 및 유효성 취약 문제가 발생하였습니다. 장비 고도화를 통해 관련 문제를 해결하기에 앞서, 서비스 로직 및 테이블 재구성을 통한 최적화 작업을 통해 문제를 해결하였습니다.

이에 관해 간단하게 소개하도록 하겠습니다.

Problems

다음과 같이 크게 두 가지 문제가 있었습니다.

  1. 성능 이슈
    1. 로그 테이블은 거대한 한 개의 테이블로 구성
    2. 데이터 누적에 따라 성능이 급격하게 저하
  2. 유효성 이슈
    1. 자바 어플리케이션에서만 유효성 체크 – 비 정상적인 사용 존재
    2. 포인트가 현금처럼 사용될 수 있으므로 반드시 필요함

Solutions

1) 파티셔닝을 통한 성능 최적화

오라클 엔터프라이즈 버전에서는 테이블 파티셔닝을 제공하지만, 아쉽게도 오라클 스탠다드에서는 관련 기능이 없습니다. 즉, 어플리케이션 레벨에서 적당히 데이터 분산을 유도하는 방법 밖에는 없습니다. 데이터를 분산하는 방법으로는 여러가지가 존재하겠지만, 저는 월별로 테이블을 분산 저장하는 방식을 사용하였습니다.

매월 하단과 같은 스키마의 테이블을 MCHIP”YYYYMM” 형식으로 생성을 합니다.

물론 해당 월 다음 달로 생성을 해야겠죠?

1
2
3
4
5
6
 Name            Type
 --------------- ------------
 SEQ             NUMBER
 USER_NO         VARCHAR2(12)
 POINT           NUMBER
 ISSUE_DATE      DATE
 Name            Type
 --------------- ------------
 SEQ             NUMBER
 USER_NO         VARCHAR2(12)
 POINT           NUMBER
 ISSUE_DATE      DATE

그리고 인덱스 필요 시 데이터 테이블스페이스와는 “물리적으로 분리”된 전용의 테이블스페이스에 생성하여 DISK I/O 비효율도 최소화 유도하였습니다.

데이터 조회는 기본적으로 월별로만 가능하며, 최근 3개월 동안만 조회할 수 있도록 하였고, 필요 시 과거 테이블을 DROP하는 방식으로 변경하였습니다. 만약 최근 3개월 데이터가 필요할 시에는 ”UNION ALL” 구문으로 데이터를 가져왔습니다.

다음은 쿼리를 월별로 생성하여 데이터를 저장하는 간단한 자바 프로그램입니다. 저는 SpringFramework 환경에서 구현했었는데, 그것보다는 알아보기 쉬운 단순 자바 프로그램으로 보여드리는 것이 좋을 것 같습니다. (설마 아래 있는 것을 그대로 쓰시는 것은 아니겠죠? ㅎㅎ)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Test {
    public static void main(String[] args) {
        DateFormat df = new SimpleDateFormat("yyyyMM");
        Date date = new Date();
 
        // 현재 기준 년월 
        String yyyymm = df.format(date).toString();
 
        // 쿼리 생성
        String sql = "INSERT INTO MCHIP"+yyyymm+" \n" +
                "(SEQ, USER_NO, POINT, ISSUE_DATE) \n" +
                "VALUES \n" +
                "(SEQ_MCHIP.NEXTVAL, ?, ?, SYSDATE)";
 
        System.out.println(sql);
    }
}
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Test {
    public static void main(String[] args) {
        DateFormat df = new SimpleDateFormat("yyyyMM");
        Date date = new Date();

        // 현재 기준 년월 
        String yyyymm = df.format(date).toString();

        // 쿼리 생성
        String sql = "INSERT INTO MCHIP"+yyyymm+" \n" +
                "(SEQ, USER_NO, POINT, ISSUE_DATE) \n" +
                "VALUES \n" +
                "(SEQ_MCHIP.NEXTVAL, ?, ?, SYSDATE)";

        System.out.println(sql);
    }
}

위와 같이 쿼리를 생성하고, 원하는 테이블에 선별적으로 데이터를 넣습니다. 조회 시에도 위와 같은 방식으로 쿼리를 생성합니다. 만약 한달 이상의 데이터가 필요하다면 UNION ALL로 쿼리를 붙여서 데이터를 조회하면 되겠죠. ^^

2) 트리거를 사용한 유효성 체크

포인트 내역을 저장하는 테이블이 있었다면, 포인트 현황을 조회하기 위한 전용 테이블 또한 존재했습니다. 포인트 현황에 저장된 점수가 사용자가 현재 소지하고 있는 포인트이며, 이를 차감하여 서비스에서 사용하는 방식으로 사용하고 있었습니다.

개인 당 한 건의 데이터만 있기 때문에, 사용자 데이터를 조회하는 것에는 큰 무리가 없었지만, 유효성을 자바 어플리케이션에서만 체크했었기 때문에 여기저기 헛점이 많은 상태였습니다. 물론 내구성이 뛰어나게 개발되었다면 큰 문제는 없었겠지만, 협력사가 시간에 쫓겨서 급하게 개발한 산출물인지라.. 아무래도.. ^^;;

자바 소스 전체를 뒤져서 모든 유효성을 체크하는 것은 거의 무리에 가까웠고, 그래서 제가 채택한 방식은 트리거였습니다. 트리거를 사용하여 사용자 포인트 유효성 여부를 DB레벨에서 체크해서 어플리케이션과 분리하자는 의도였죠.

MCHIP201209 테이블에 포인트가 내역이 들어가는 동시에 유효성 체크 후 정상적이면 포인트 현황 테이블에 반영하는 트리거입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
CREATE OR REPLACE TRIGGER TRG01_MCHIP201209
BEFORE INSERT
ON MCHIP201209
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
DECLARE
  POINT NUMBER;
BEGIN
  /*** 현재 사용자 포인트 조회 ***/
  SELECT POINT INTO POINT FROM MCHIP_INFO
  WHERE USER_NO = :NEW.USER_NO;
  … 중략…
 
  /*** 포인트 유효성 체크  ***/
  IF POINT - :NEW.POINT < 0 THEN
    RAISE_APPLICATION_ERROR(-20001,'Not enough point!!');
  END IF;
 
  /*** 포인트 현황 업데이트 ***/
  UPDATE MCHIP_INFO SET POINT = POINT + POINT_NEW
  WHERE USER_NO = :NEW.USER_NO;
END;
/
CREATE OR REPLACE TRIGGER TRG01_MCHIP201209
BEFORE INSERT
ON MCHIP201209
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
DECLARE
  POINT NUMBER;
BEGIN
  /*** 현재 사용자 포인트 조회 ***/
  SELECT POINT INTO POINT FROM MCHIP_INFO
  WHERE USER_NO = :NEW.USER_NO;
  … 중략…

  /*** 포인트 유효성 체크  ***/
  IF POINT - :NEW.POINT < 0 THEN
    RAISE_APPLICATION_ERROR(-20001,'Not enough point!!');
  END IF;

  /*** 포인트 현황 업데이트 ***/
  UPDATE MCHIP_INFO SET POINT = POINT + POINT_NEW
  WHERE USER_NO = :NEW.USER_NO;
END;
/

Conclusion

오래전에 성능을 최적화한 내용을 정리하였습니다.

당시 서버에 과부하로 인하여 서버 고도화 및 장비 도입을 위한 투자를 검토 중이었으나, 서비스 로직 재구성 이후 서버가 안정적이었기 때문에 기존 장비로 서비스를 진행하였습니다. 게다가 현재 기존 장비 사용률이 CPU 기준 80~90%였던 상황이 10~20%로 유지되는 쾌거를 거두었죠.

데이터 처리량을 최소로 유도하는 것이 성능 최적화의 첫걸음이라는 것을 느낀 경험이었습니다.

좋은 포스팅으로 다시 찾아뵐께요^^;

Tags: ,

DB Link와 Export/Import를 활용한 데이터 이관 성능 리포트

2012-04-13 by gywndi | No Comments | Filed in Oracle, Research

안녕하세요. 한동안 MySQL에 빠져 있다가, 최근 Oracle 데이터 이관 작업 도중 재미난 사례 공유 합니다. DB Link를 통한 CTAS(Create Table As Select)와 Export/Import를 통한 데이터 이관 비교입니다.

서비스 요구 사항

서비스 DBMS 버전 : Oracle 9i
전체 데이터 파일 사이즈 : 120G (인덱스 포함)
타겟 테이블 데이터 사이즈 : 26G (인덱스 제외)
네트워크 속도 : 100Mbps (max: 12.5MB/s)
일 1회 현재 서비스 데이터 동기화 수행
모든 작업은 “자동화”하여 운영 이슈 최소화

위 환경을 고려하였을 때, 전체 데이터 파일 Copy는 동기화 시간 및 스토리지 낭비 요소가, Archive Log 활용하기에는 운영 이슈가 존재했습니다.

그래서 결정한 것이 필요한 테이블만 이관하자는 것이고, 가장 효율적인 방안을 모색하기 위해 DB Link와 Import/Export 두 가지 성능을 비교해보았습니다.

DB 환경 구축

Oracle DBMS 환경은 장비 효율을 높이기 위해서 Oracle VM 상에 가상 머신으로 구성을 하였습니다. Oracle VM에 대한 소개는 추후 천천히 소개를 드릴께요^^

서버 구성

서버 구성

Export/Import 결과

아래 그림과 같이 nfs Server/Client 구성을 하였는데, 타겟 테이블을 별도로 Export 후, 해당 파일을 nfs로 직접 끌어와서 데이터를 가져오는 방식입니다.

Export/Import를 위한 nfs 서버 구성

Export/Import를 위한 nfs 서버 구성

Export/Import 결과

Export 시간은 약 20분, Import시간은 약 60분 그리고 사전 작업 시간을 고려해봤을 때, 데이터만 이관할 시 90분이라는 시간이 소요되었습니다. 하루에 1시간 30분 정도 동기화 시간을 제공하면 되니 크게 나쁜 결과는 아니었습니다.

그러나 Import 수행되는 동안 alert.log를 확인을 해보니 Log Switch가 너무 빈도있게 발생(1분 단위)하였으며, 아래와 같이 Log가 데이터 파일로 Flush되지 않아서 대기하는 상황이 발생하였습니다.

Import 시 Alert 로그 현황

DB Link 결과

Export/Import 시간 체크 후 Redo Log 사용 없이 직접적으로 데이터를 Write할 수 있다면 더욱 빠른 데이터 이관이 가능할 것이라고 판단이 되어 이번에는 DB Link를 통한 CTAS(Create Table As Select) 방법으로 접근을 해보았습니다. 물론 CTAS에서 반드시 NOSLOGGING 옵션을 줘야겠죠 ^^

Oracle VM 서버에서 환경에 맞게 계정 별로 DB Link를 생성을 하고 하단과 같이 테이블 Drop 후 Create Table As Select 구문을 실행합니다.

1
2
3
4
SQL> DROP TABLE TABLE01;
SQL> CREATE TABLE TABLE01 NOLOGGING
   > AS
   > SELECT * FROM TABLE01@DB_LINK;
SQL> DROP TABLE TABLE01;
SQL> CREATE TABLE TABLE01 NOLOGGING
   > AS
   > SELECT * FROM TABLE01@DB_LINK;

Oracle VM에서는 물리적으로 다른 장비 세 대로부터 동시에 데이터를 받으며, 물리적인 장비 안에는 각각 두 개의 서비스 계정이 포함됩니다.

결과는 다음과 같습니다.

DB Link Result

위와 마찬가지로 동시에 실행을 했기 때문에 가장 오래 걸린 서비스가 최종 소요된 시간이며, 00:00~ 00.19:13 에 종료되었으니 대략 20분 소요되었습니다. 앞선 결과에서 90분 소요되던 것을 20분으로 줄였으니, 상당히 괜찮은 결과이네요^^

물론 Alert Log에 Log Switch 관련 메시지는 나오지 않았습니다.

Conclusion

DB Link를 활용하여 데이터를 이관하는 것이 압도적으로 빠른 결과였습니다.

그러나 항상 DB Link가 좋은 것은 아닙니다. 다행히 대상 테이블에는 LOB 관련 필드는 없었지만, 만약 LOB 필드가 있었다면 어쩔 수 없이 Export/Import 방식을 써야만 했겠죠.

데이터 이관을 위한 여러가지 방안이 있겠지만, 한번 쯤은 두 가지 방법의 장단점을 따져보고 싶었는데 좋은 기회가 되어서 내용 공유 드립니다

Posted by redkite
, |

최근에 달린 댓글

최근에 받은 트랙백

글 보관함