오라클 도움말 파일

 

 

Oracle DB Help.HLP

   
 

Plshelp.hlp

PL SQL   Helper  
 

Sqlcodes.chm

SQL Error code  
 

Sqlhelp.hlp

SQL DML, DDL, FUNCTION  
 

sqlsyntax.chm

SQL Syntax 설명  (DML, DDL)  
       

 

'(DB) Oracle > 기타' 카테고리의 다른 글

Oracle - RMAN  (0) 2017.01.22
Oracle - Flashback_Table  (0) 2017.01.22
Oracle - Transportable Tablespaces  (0) 2017.01.22
Oracle - Top SQL 튜닝하기  (0) 2017.01.22
Oracle - Redo buffer 관련 Wait  (0) 2017.01.22
Posted by 농부지기
,

Oracle - RMAN

(DB) Oracle/기타 2017. 1. 22. 17:21

Oracle - RMAN  ] 

 

RMAN

 
 한층 강력해진 RMAN 유틸리티는 개선된 증분백업, 증분백업의 오프라인 복구, 복구 파일 미리보기, resetlog를 이용한 복구, 파일 압축 등에 관련한 다양한 신기능을 제공합니다.
 
RMAN이 오라클 데이타베이스 백업 툴의 실질적인 표준으로서 인정되고 있다는 사실은 대부분의 사람들이 동의할 것입니다. 하지만 RMAN의 이전 버전에 문제가 많았던 것도 사실입니다. 필자 역시 RMAN의 기능적인 한계에 불만을 가진 사용자 중 하나였습니다.
 Oracle Database 10g는 이러한 문제의 많은 부분을 해결하고 RMAN을 한층 강력하고 유용한 툴로 변화시켰습니다. 그러면 한 번 살펴보기로 합시다.
 
증분 백업 (Incremental Backup) 기능의 개선
 
RMAN은 이전부터 증분 백업을 위한 옵션을 제공해 왔습니다. 하지만 이 기능을 실제로 사용하는 경우는 극히 드물었습니다.
 
증분 백업은 마지막으로 증분 백업이 수행된 이후 변경된 블록만을 백업하는 방식입니다. 예를 들어 Day 1에 전체 백업(level_0)이 수행되고 Day 2와 Day 3에 두 차례의 증분 백업(level_1)이 수행된 경우를 생각해 봅시다. 두 개의 증분 백업은 각각 Day 1과 Day 2, Day 2와 Day3 사이에 변경된 블록만을 포함하고 있습니다. 이와 같은 백업 정책을 사용함으로써 백업 사이즈와 백업에 필요한 디스크 공간을 절감하고, 백업 윈도우를 단축할 수 있을 뿐 아니라 네트워크를 통해 전송되는 데이타 양을 줄일 수 있습니다.
 
증분 백업은 데이타 웨어하우스 환경에서 특히 유용합니다. 데이타 웨어하우스 작업의 많은 부분은 NOLOGGING 모드로 수행되므로 변경 내역이 아카이브 로그 파일에 저장되지 않으며, 따라서 미디어 복구가 불가능합니다. 데이타 웨어하우스 환경의 데이타 규모와 이 데이타의 대부분이 거의 변경되지 않는다는 사실을 고려할 때, 전체 백업은 효과적이지 못하며 현실적으로 불가능할 수도 있습니다. 그 대신 RMAN을 사용해서 증분 백업을 수행하는 것이 좋은 대안이 될 수 있습니다..
 
그렇다면 DBA들이 증분 백업 방식을 이용하지 않는 이유는 무엇일까요? Oracle9i와 그 이전 버전의 경우, RMAN은 증분 백업을 수행하기 위해 전체 데이타 블록에 대한 스캔을 수행했습니다. 이러한 작업이 시스템에 너무 큰 부담을 주기 때문에 증분 백업이 효율적이지 않다는 평가를 받게 된 것입니다.
 
Oracle Database 10g의 RMAN 기능은 이러한 점에서 크게 개선되었습니다. Oracle Database 10g는 (파일시스템의 저널과 유사한 용도를 갖는) 별도의 파일을 통해 마지막 백업 이후 변경된 블록을 추적합니다. RMAN은 (전체 데이타 블록을 스캔하는 대신) 이 파일을 참조하여 어떤 블록을 백업해야 하는지 결정합니다.
 
아래 명령을 통해 추적 메커니즘(tracking mechanism)을 활성화시킬 수 있습니다:
SQL> alter database enable block change tracking using file '/rman_bkups/change.log';
 
위 명령은 /rman_bkups/change.log 바이너리 파일을 생성하고 이 파일에 블록 변경 내역을 저장합니다. 아래 명령을 사용하면 추적 메커니즘을 비활성화할 수 있습니다:
SQL> alter database disable block change tracking;
 
현재 블록 변경 내역의 추적이 수행되고 있는지 확인하려면 아래 쿼리를 사용합니다:
SQL> select filename, status from v$block_change_tracking;
 
Flash Recovery Area
 
Oracle9i에서 처음 소개된 Flashback 쿼리는 언두 테이블스페이스를 사용하여 이전 버전으로의 “회귀(flash-back)”을 수행하며, 그 원리상 아주 오래 전의 과거 시점으로는 되돌릴 수 없다는 한계를 갖습니다. 이러한 문제의 대안으로서 제공되는 Flash Recovery는 리두 로그와 유사한 형태의 flashback log을 생성함으로써, 원하는 특정 시점으로 데이타베이스의 상태를 되돌릴 수 있게 합니다. Flash Recovery를 사용하려면 먼저 데이타베이스에 flash recovery area를 생성하고, 그 크기를 정의한 뒤 아래와 같은 SQL 명령을 통해 데이타베이스를 flash recovery mode로 설정하면 됩니다:
alter system set db_recovery_file_dest = '/ora_flash_area';
alter system set db_recovery_file_dest_size = 2g;
alter system set db_flashback_retention_target = 1440;
alter database flashback on; 
 
Flashback 기능을 사용하려면 데이타베이스가 아카이브 로그 모드로 설정되어 있어야 합니다. Flash Recovery가 활성화되면 디렉토리 /ora_flash_area에 최대 2GB 크기의 Oracle Managed File이 생성됩니다. 모든 데이타베이스 변경 사항은 이 파일에 기록되며, 이 파일을 사용하여 과거의 특정 시점으로 데이타베이스를 복구할 수 있습니다.
 
RMAN은 /ora_flash_area 디렉토리를 디폴트 백업 파일 저장위치로 사용하며, 따라서 백업 파일은 테이프가 아닌 디스크에 저장됩니다. 이 경우 백업 파일을 얼마나 오랫동안 보존할 것인지 설정할 수 있으며, 정의된 보존 기간이 지난 후 추가 공간이 필요해지면 파일은 자동으로 삭제됩니다.
 
Flash recovery area가 반드시 파일시스템 또는 디렉토리일 필요는 없으며, ASM(Automatic Storage Management) 디스크그룹으로 지정할 수도 있습니다. Flash recovery area를 ASM 디스크그룹으로 지정하려면 아래와 같은 명령을 사용합니다:
alter system set db_recovery_file_dest = '+dskgrp1';
 
ASM과 RMAN을 함께 사용하면, 별도의 추가비용 없이 Serial ATA 드라이브 또는 SCSI 드라이브 등의 저가형 디스크를 사용해서 뛰어난 확장성과 가용성을 갖춘 스토리지 환경을 구성할 수 있습니다. (ASM에 대한 자세한 설명은 이 시리즈의 제 8 주 연재를 참고하시기 바랍니다.) 이와 같이 구성함으로써 테이프 기반 솔루션만큼 저렴한 비용으로 디스크 백업 환경을 구축하는 동시에 백업 프로세스의 실행 속도를 향상시킬 수 있습니다.
 
이 접근법의 또 한 가지 장점으로 사용자 실수에 대한 보호 기능을 들 수 있습니다. ASM 파일은 일반적인 파일시스템 환경이 아니기 때문에, DBA와 시스템 관리자의 실수로 손상될 가능성이 매우 적습니다.
 
증분 병합 (Incremental Merge)
 
아래와 같은 백업 스케줄을 갖는 환경을 가정해 봅시다:
 
일요일 - Level 0 (전체 백업), tag level_0
월요일 - Level 1 (증분 백업), tag level_1_mon
Tuesday - Level 1 (incremental) with tag level_1_tue

... (이하 생략)
 
이와 같은 백업정책 하에서, 토요일에 데이타베이스 장애가 발생한 경우, 10g 이전의 환경에서는 tag level_0를 복구하고 나머지 6개의 증분 백업본을 모두 복구해야만 했습니다. 이러한 작업에는 매우 오랜 시간이 걸리며, 이는 실제로 DBA가 증분 백업을 즐겨 사용하지 않는 이유 중 하나이기도 합니다.
 
Oracle Database 10g RMAN은 이러한 작업환경을 극적으로 개선했습니다. Oracle Database 10g RMAN의 증분 백업 명령은 아래와 같은 형태로 수행됩니다:
RMAN> backup incremental level_1 for recover of copy with tag level_0 database;
 
위에서 우리는 RMAN이 incremental level_1 백업을 수행하고 그 결과를 level_0의 전체 백업본과 병합(merge)하도록 설정했습니다. 이 명령을 수행하면 그 날의 전체 백업 이미지를 갖는 level_0 백업본이 새로이 생성됩니다.
 
예를 들어, 화요일에 수행된 증분 백업(level_1)은 이전의 전체 백업(level_0)과 병합되어 화요일 버전의 새로운 전체 백업본이 생성됩니다. 마찬가지로 토요일에 수행된 증분백업 역시, 금요일의 전체백업본과 병합되어 새로운 전체백업으로 저장됩니다. 따라서 토요일에 데이타베이스가 장애가 발생한다면, level_0 백업본 하나와 아카이브 로그 몇 개만을 이용하여 데이타베이스를 복구할 수 있습니다. 이러한 방법으로 복구에 소요되는 시간을 극적으로 절감하고, 백업 속도를 향상시키는 한편, 전체 백업의 수행 횟수를 줄일 수 있습니다.
 
압축 파일(Compressed Files)
 
Flash recovery area에 디스크 백업을 보관하는 경우에도, 디스크 공간의 한계라는 문제는 여전히 남습니다. 특히 네트워크를 통해 백업을 수행하는 환경이라면, 백업본의 크기를 최대한 작게 유지하는 구성이 권장됩니다. 이를 위해 Oracle Database 10g RMAN은 백업 명령에 새로운 압축 옵션을 추가하였습니다:
RMAN> backup as compressed backupset incremental level 1 database;
 
COMPRESSED 키워드가 사용된 형태를 주의해 보시기 바랍니다. 이 키워드를 사용하는 경우 백업 데이타의 압축을 통해 백업 성능을 향상할 수 있으며, 복구 과정에서는 별도의 압축해제 작업 없이도 RMAN이 파일을 읽어 들일 수 있습니다. 압축을 설정한 경우, 백업 수행 과정에서 아래와 같은 메시지가 출력됩니다.
channel ORA_DISK_1: starting compressed incremental level 1 datafile backupset
또, RMAN list output 명령을 통해 백업 압축 설정 여부를 확인할 수도 있습니다.
RMAN> list output;

BS Key  Type LV Size       Device Type Elapsed Time Completion Time
------- ---- -- ---------- ----------- ------------ ---------------
3       Incr 1  2M         DISK        00:00:00     26-FEB-04      
        BP Key: 3   Status: AVAILABLE  Compressed: YES  Tag: TAG20040226T100154
        Piece Name: /ora_flash_area/SMILEY10/backupset/2004_02_26/o1_mf_ncsn1_TAG20040226T100154_03w2m3lr_.bkp
  Controlfile Included: Ckp SCN: 318556       Ckp time: 26-FEB-04
  SPFILE Included: Modification time: 26-FEB-04
 
모든 압축 알고리즘이 그러하듯, 이 방법을 쓰는 경우 CPU에 추가적인 부담을 주게 됩니다. 반면, 더 많은 RMAN 백업을 디스크에 보관할 수 있다는 장점이 있습니다. 또 Physical Standby Database에서 RMAN 백업을 실행하면 원본 서버에 부담을 주지 않고 백업을 수행할 수 있습니다.
 
Look Before You Leap: Recovery Preview
 
Oracle Database 10g의 RMAN은 한 걸음 더 나아가 복구 작업에 사용할 수 있는 백업본을 미리 확인하는 Recovery Preview 기능을 지원합니다.
RMAN> restore database preview;
위 작업의 실행 결과는 Listing 1에서 확인하실 수 있습니다. 테이블스페이스 별로 백업본을 개별적으로 확인하는 것도 가능합니다:
restore tablespace users preview;
 
Preview 기능을 활용하여 백업 인프라스트럭처가 정상적으로 운영되고 있는지 정기적으로 점검할 수 있습니다.
 
Resetlog와 복구 작업
 
커런트 온라인 리두 로그(current online redo log) 파일이 손실되어, 불완전한 데이타베이스 복구(incomplete database recovery)를 수행할 수 밖에 없는 상황을 가정해 봅시다 (이러한 경우는 흔치 않지만 실재로 존재합니다). 이 경우 가장 큰 문제는 resetlog입니다. 불완전 복구를 수행한 뒤에 resetlog 키워드를 사용하여 log thread의 시퀀스 넘버를 1로 재설정하고 데이타베이스를 오픈해야 하는데, 이렇게 하는 경우 이전에 백업된 데이타가 무용지물이 될 뿐 아니라 복구 작업 자체가 더욱 어려워지게 됩니다.
 
Oracle9i와 그 이전 버전에서는 데이타베이스를 resetlog 이전의 상태로 복구하려면 전혀 새로운 환경에 데이타베이스를 새로 구축할 수 밖에 없었습니다. Oracle Database 10g에서는 이러한 문제가 해결되었습니다. 컨트롤 파일에 추가된 새로운 기능 덕분에, RMAN이 resetlog 수행 이전 또는 이후의 모든 백업 이미지를 복구에 이용할 수 있게 된 것입니다. 또 백업을 수행하기 위해 데이타베이스를 셧다운할 필요도 없게 되었습니다. 이 기능을 사용하면, resetlog 작업 이후 데이타베이스를 바로 오픈하고 운영을 재개하는 것이 가능합니다.
 
Ready for RMAN
 
Oracle Database 10g RMAN은 한층 향상된 백업 관리 툴로 거듭 태어났습니다. 증분 백업에 관련한 기능 개선만으로도 RMAN은 더 이상 무시할 수 없는 툴이 되었습니다.
 
Oracle Database 10g RMAN에 대한 보다 자세한 정보는,“Oracle Database Backup and Recovery Basics 10g Release 1 (10.1)” 문서의 Chapter 4을 참고하시기 바랍니다.
 

출처: http://www.oracle.com/technology/global/kr/pub/articles/10gdba/week9_10gdba.html

'(DB) Oracle > 기타' 카테고리의 다른 글

Oracle - 도움말 파일  (0) 2017.01.22
Oracle - Flashback_Table  (0) 2017.01.22
Oracle - Transportable Tablespaces  (0) 2017.01.22
Oracle - Top SQL 튜닝하기  (0) 2017.01.22
Oracle - Redo buffer 관련 Wait  (0) 2017.01.22
Posted by 농부지기
,

[ Oracle - Flashback 테이블 ]     

 

Flashback 테이블

 
 실수로 삭제한 테이블을 손쉽게 다시 유효화할 수 있는 Oracle Database 10g의 Flashback 테이블 기능
 
매우 중요한 테이블을 실수로 삭제하여 즉시 복구해야 하는 상황은 생각보다 자주 일어나는 시나리오입니다. (때로는 이처럼 불운한 사용자가 DBA일 수도 있습니다!)
 
Oracle9i Database에는 Flashback 질의 옵션 개념이 도입되어 데이타를 과거의 시점에서부터 검색하지만, 테이블 삭제 같은 DDL 작업을 순간적으로 되돌릴 수는 없습니다. 이 경우 유일한 수단은 다른 데이타베이스에서 테이블스페이스 적시 복구를 사용한 다음, 엑스포트/임포트 또는 기타 메서드를 사용해 현재 데이타베이스에 테이블을 다시 생성하는 것입니다. 이 프로시저를 수행하려면 복제를 위해 다른 데이타베이스를 사용하는 것은 물론, DBA의 많은 노력과 귀중한 시간이 요구됩니다.
 하지만 Oracle Database 10g의 Flashback 테이블 기능으로 들어가면 몇 개의 문만 실행하여 삭제된 테이블을 간단히 검색할 수 있습니다. 그럼, 지금부터 이 기능의 작동 원리에 대해 알아보도록 하겠습니다.
 
자유로운 테이블 삭제
먼저, 현재 스키마의 테이블을 확인해 봅시다.
SQL> select * from tab;

TNAME                    TABTYPE  CLUSTERID
------------------------ ------- ----------
RECYCLETEST              TABLE
그런 다음, 아래와 같이 고의로 테이블을 삭제합니다.
SQL> drop table recycletest;

Table dropped.
이제 테이블의 상태를 확인합니다.
SQL> select * from tab;

TNAME                          TABTYPE  CLUSTERID
------------------------------ ------- ----------
BIN$04LhcpndanfgMAAAAAANPw==$0 TABLE
 
RECYCLETEST 테이블이 사라졌지만 새 테이블인 BIN$04LhcpndanfgMAAAAAANPw==$0이 있다는 점에 주목합니다. 좀 더 자세히 설명하면 삭제된 테이블 RECYCLETEST가 완전히 사라지는 대신 시스템 정의 이름으로 이름이 변경된 것입니다. 이 테이블은 여전히 동일한 테이블스페이스에 있으며 원래 테이블과 구조도 동일합니다. 테이블에 인덱스 또는 트리거가 정의되어 있는 경우, 마찬가지로 테이블과 동일한 명명 규칙을 사용하여 이름이 변경됩니다. 프로시저 같은 종속적인 소스는 무효화되지만, 대신 원래 테이블의 트리거 및 인덱스가 이름이 변경된 테이블인 BIN$04LhcpndanfgMAAAAAANPw==$0에 들어가 삭제된 테이블의 완전한 객체 구조를 보존합니다.
 
테이블 및 연관된 객체는 PC에 있는 것과 유사한 “휴지통(RecycleBin)”이라고 하는 논리적 컨테이너에 들어갑니다. 하지만 이들 객체가 이전에 있던 테이블스페이스에서 옮겨지는 것은 아니며 계속 해당 테이블스페이스에서 공간을 차지하고 있습니다. 휴지통은 단순히 삭제된 객체의 목록을 만드는 논리적 구조입니다. 휴지통의 컨텐트를 확인하려면 SQL*Plus 프롬프트에서 다음 명령을 사용합니다(SQL*Plus 10.1이 있어야 함).
SQL> show recyclebin

ORIGINAL NAME    RECYCLEBIN NAME                OBJECT TYPE  DROP TIME
---------------- ------------------------------ ------------ ------------------
RECYCLETEST      BIN$04LhcpndanfgMAAAAAANPw==$0 TABLE        2004-02-16:21:13:31
 
이렇게 하면 테이블의 원래 이름인 RECYCLETEST는 물론, 삭제된 후 생성된 새 테이블 이름과 동일한 휴지통에서의 새 이름이 표시됩니다. (참고: 정확한 이름은 플랫폼별로 다를 수 있습니다.) 테이블을 다시 유효화하기 위해서는 FLASHBACK TABLE 명령만 사용하면 됩니다.
SQL> FLASHBACK TABLE RECYCLETEST TO BEFORE DROP;

FLASHBACK COMPLETE.

SQL> SELECT * FROM TAB;

TNAME                          TABTYPE  CLUSTERID
------------------------------ ------- ----------
RECYCLETEST                    TABLE
 
, 테이블이 정말 간단히 유효화되지 않습니까? 지금 휴지통을 확인하면 비어 있습니다.
여기서 유의할 점은 테이블을 휴지통에 넣는다고 해도 원래 테이블스페이스의 공간이 제거되는 것은 아니라는 것입니다. 공간을 제거하려면 다음을 사용해 휴지통을 지워야 합니다.
PURGE RECYCLEBIN;
하지만 Flashback 기능을 사용하지 않고 테이블을 완전히 삭제하려면 어떻게 해야 할까요? 이 경우 다음을 사용하면 테이블을 영구적으로 삭제할 수 있습니다.
DROP TABLE RECYCLETEST PURGE;
이 명령을 실행하면 테이블 이름이 휴지통 이름으로 변경되는 것이 아니라, 10g 이전 버전에서처럼 영구적으로 삭제됩니다.
 
휴지통 관리
 
이 프로세스에서 테이블을 완전히 삭제하지 않아 테이블스페이스를 해제하지 않은 상태에서 삭제된 객체가 테이블스페이스의 모든 공간을 차지하면 어떤 일이 발생할까요?
 
답은 간단합니다. 그 같은 상황은 결코 발생하지 않습니다. 데이타 파일에 데이타를 추가할 공간을 확보해야 할 정도로 휴지통 데이타가 테이블스페이스로 꽉 차는 상황이 발생하면 테이블스페이스는 이른바 “공간 압축” 상태에 들어갑니다. 위의 시나리오에서 객체는 선입선출 방식으로 휴지통에서 자동으로 지워지며, 종속된 객체(예: 인덱스)는 테이블보다 먼저 제거됩니다.
 
마찬가지로 특정 테이블스페이스에 정의된 사용자 할당량에도 공간 압축이 발생할 수 있습니다. 테이블에는 사용 가능한 공간이 충분하지만 사용자는 할당된 공간이 부족할 수 있습니다. 이러한 상황에서 Oracle은 해당 테이블스페이스의 사용자에 속한 객체를 자동으로 지웁니다.
 
이 외에도 여러 가지 방법으로 휴지통을 수동으로 제어할 수 있습니다. 삭제한 후 휴지통에서 TEST라고 명명된 특정 테이블을 삭제하려면 다음을 실행하거나,
PURGE TABLE TEST;
 
아래와 같이 해당 휴지통 이름을 사용합니다.
PURGE TABLE "BIN$04LhcpndanfgMAAAAAANPw==$0";
 
이 명령을 실행하면 휴지통에서 TEST 테이블과 인덱스, 제약 조건 등과 같은 모든 종속 객체가 삭제되어 일정 공간을 확보하게 됩니다. 하지만 휴지통에서 인덱스를 영구적으로 삭제하려면 다음을 사용합니다.
purge index in_test1_01;
 
이렇게 하면 인덱스만 제거되며 테이블의 복사본은 휴지통에 남아 있습니다.
때로는 상위 레벨에서 지우는 것이 유용할 수도 있습니다. 예를 들어, 테이블스페이스 USERS의 휴지통에 있는 모든 객체를 지워야 한다면 다음을 실행합니다.
PURGE TABLESPACE USERS;
 
휴지통에서 해당 테이블스페이스의 특정 사용자만 지워야 하는 경우도 있습니다. 이 접근방법은 사용자가 많은 수의 과도 상태 테이블을 생성 및 삭제하는 데이타 웨어하우스 유형의 환경에 유용합니다. 다음과 같이 위의 명령을 수정해 지우기 작업을 특정 사용자만으로 제한할 수 있습니다.
PURGE TABLESPACE USERS USER SCOTT;
 
사용자 SCOTT는 다음 명령으로 휴지통을 지웁니다.
PURGE RECYCLEBIN;
 
DBA는 다음을 사용해 테이블스페이스의 모든 객체를 지울 수 있습니다.
PURGE DBA_RECYCLEBIN;
 
위에서 살펴본 것처럼 휴지통은 사용자의 특정한 요구에 맞는 다양한 방식으로 관리할 수 있습니다.
 
테이블 버전 및 Flashback
 
다음과 같이 동일한 테이블을 여러 번 생성 및 삭제해야 하는 경우도 흔히 발생합니다.
CREATE TABLE TEST (COL1 NUMBER);
INSERT INTO TEST VALUES (1);
COMMIT;
DROP TABLE TEST;
CREATE TABLE TEST (COL1 NUMBER);
INSERT INTO TEST VALUES (2);
COMMIT;
DROP TABLE TEST;
CREATE TABLE TEST (COL1 NUMBER);
INSERT INTO TEST VALUES (3);
COMMIT;
DROP TABLE TEST;
 
여기서 TEST 테이블을 순간적으로 되돌린다면 COL1 열의 값은 어떻게 될까요? 기존의 개념에서 보면 휴지통에서 테이블의 첫 번째 버전이 검색되고 COL1 열의 값은 1이 될 것입니다. 하지만 실제로는 첫 번째가 아닌 테이블의 세 번째 버전이 검색되므로 COL1 열의 값은 1이 아닌 3이 됩니다.
 
이 때 삭제된 테이블의 다른 버전을 검색할 수도 있습니다. 하지만 TEST 테이블이 존재하는 이러한 작업이 불가능한데, 이 경우 다음 두 가지를 선택할 수 있습니다.
  • 다음과 같이 이름 바꾸기 옵션을 사용합니다.
    FLASHBACK TABLE TEST TO BEFORE DROP RENAME TO TEST2;
    FLASHBACK TABLE TEST TO BEFORE DROP RENAME TO TEST1;
    
    이렇게 하면 테이블의 첫 번째 버전은 TEST1으로, 두 번째 버전은 TEST2로 다시 유효화됩니다. 또한 TEST1 및 TEST2에서 COL1의 값은 각각 1과 2가 됩니다. 또는
  • 복원할 테이블의 특정 휴지통 이름을 사용합니다. 이를 위해 먼저 테이블의 휴지통 이름을 식별한 후 다음을 실행합니다.
    FLASHBACK TABLE "BIN$04LhcpnoanfgMAAAAAANPw==$0" TO BEFORE DROP RENAME TO TEST2;
    FLASHBACK TABLE "BIN$04LhcpnqanfgMAAAAAANPw==$0" TO BEFORE DROP RENAME TO TEST1;
    
    이렇게 하면 삭제된 테이블의 두 가지 버전이 복원됩니다.
 
주의 사항
 
삭제 취소 기능을 사용하면 테이블의 이름이 원래대로 돌아가지만 인덱스 및 트리거 같은 연관된 객체는 그렇지 않으며 계속 휴지통 이름으로 남아 있습니다. 또한 뷰 및 프로시저 같이 테이블에 정의된 소스는 재컴파일되지 않으며 무효화된 상태로 남게 됩니다. 이러한 이전 이름들은 수동으로 검색한 다음 순간적으로 되돌린 테이블에 적용해야 합니다.
 
이 정보는 USER_RECYCLEBIN으로 명명된 뷰에서 관리됩니다. 테이블을 순간적으로 되돌리기 전에 다음 질의를 사용해 이전 이름을 검색합니다.
SELECT OBJECT_NAME, ORIGINAL_NAME, TYPE
FROM USER_RECYCLEBIN
WHERE BASE_OBJECT = (SELECT BASE_OBJECT FROM USER_RECYCLEBIN
WHERE ORIGINAL_NAME = 'RECYCLETEST')
AND ORIGINAL_NAME != 'RECYCLETEST';

OBJECT_NAME                    ORIGINAL_N TYPE
------------------------------ ---------- --------
BIN$04LhcpnianfgMAAAAAANPw==$0 IN_RT_01   INDEX
BIN$04LhcpnganfgMAAAAAANPw==$0 TR_RT      TRIGGER
 
테이블을 순간적으로 되돌리면 RECYCLETEST 테이블의 인덱스 및 트리거에는 OBJECT_NAME 열에 나타난 이름이 지정됩니다. 위의 질의에서는 원래 이름을 사용해 객체의 이름을 다음과 같이 변경할 수 있습니다.
ALTER INDEX "BIN$04LhcpnianfgMAAAAAANPw==$0" RENAME TO IN_RT_01;
ALTER TRIGGER "BIN$04LhcpnganfgMAAAAAANPw==$0" RENAME TO TR_RT;
 
한가지 유의해야 할 예외는 비트맵 인덱스입니다. 비트맵 인덱스를 삭제하면 휴지통에 들어가지 않으므로 검색할 수 없습니다. 또한 뷰에서 제약 조건 이름을 검색할 수 없습니다. 따라서 이 인덱스의 이름은 다른 소스에서 변경해야 합니다.
 
Flashback 테이블의 다른 용도
 
Flashback Drop Table에는 테이블 삭제 작업을 되돌리는 것 외에도 다른 기능이 있습니다. Flashback 질의와 마찬가지로 이를 사용해 테이블을 다른 시점으로 다시 유효화하여 전체 테이블을 “이전” 버전으로 바꿀 수 있습니다. 예를 들어, 다음 문을 사용하면 테이블을 시스템 변경 번호(SCN) 2202666520으로 다시 유효화합니다.
FLASHBACK TABLE RECYCLETEST TO SCN 2202666520;
이 기능은 Oracle Data Pump 기술로 다른 테이블을 생성하고 Flashback으로 테이블을 해당 SCN의 데이타 버전으로 채운 다음, 원래의 테이블을 새 테이블로 바꿉니다. 테이블을 어느 정도까지 순간적으로 되돌릴 수 있는지 확인하려면 Oracle Database 10g의 버전 관리 기능을 사용합니다. (자세한 내용은 이 시리즈의 1주 부분을 참조하십시오.) 또한 Flashback 절에 SCN 대신 타임 스탬프를 지정할 수도 있습니다.
 
 
 
 

 

 

출처: http://www.oracle.com/technology/global/kr/pub/articles/10gdba/week5_10gdba.html

'(DB) Oracle > 기타' 카테고리의 다른 글

Oracle - 도움말 파일  (0) 2017.01.22
Oracle - RMAN  (0) 2017.01.22
Oracle - Transportable Tablespaces  (0) 2017.01.22
Oracle - Top SQL 튜닝하기  (0) 2017.01.22
Oracle - Redo buffer 관련 Wait  (0) 2017.01.22
Posted by 농부지기
,

Oracle - Transportable Tablespaces ]     

 

Transportable Tablespaces

 
10g의 transportable tablespace는 서로 다른 플랫폼 간의 데이타 이동을 지원하므로, 데이타 배포 작업을 한층 쉽고 빠르게 수행할 수 있습니다. 또, external table을 이용한 다운로드 기능을 활용하여 데이타 이동 및 변환 작업을 보다 효율적으로 완료할 수 있습니다.
 데이타베이스 간의 데이타 이동 작업을 어떻게 처리하십니까? 여러 가지 방법이 있겠지만 그 중에서도 가장 돋보이는 것이 바로 transportable tablespace입니다. Transportable tablespace는 대상 테이블스페이스 집합이 자체적으로 다른 테이블스페이스에 있는 오브젝트를 참조하는 것이 없는 “self-contained”이어야 하며, 테이블스페이스를 읽기전용 상태로 설정한 뒤 메타데이타만을 먼저 익스포트(export)하고, OS 레벨의 카피 작업을 통해 데이타파일을 타겟 플랫폼으로 복사한 다음, 데이타 딕셔너리에 메타데이타를 임포트(이 프로세스를 “plugging”이라 부르기도 합니다.)하는 방식으로 데이타를 전송합니다. .
 
OS 파일 카피 작업은 SQL*Loader를 이용한 익스포트/임포트 작업과 같은 데이타 이동 방식에 비해 일반적으로 훨씬 빠른 처리 성능을 보입니다. 하지만 Oracle9i Database와 그 이전 버전의 경우, 소스 데이타베이스와 타겟 데이타베이스가 동일 OS플랫폼으로 구성되어야 한다는 제약사항 때문에 그 유용성에 제한을 받았습니다 (예를 들어 Solaris와 HP-UX 간의 테이블스페이스 전송은 불가능했습니다).
 
Oracle Database 10g에서는 이러한 기능 제약이 사라졌습니다. OS byte order가 동일하기만 하면 서로 다른 플랫폼 간이라도 테이블스페이스 전송이 가능해졌습니다. byte order에 대한 상세한 설명은 이 세션의 범위를 넘어서지만, 간략히 살펴보면 Windows를 포함하는 일부 운영체제의 경우, 멀티-바이트 바이너리 데이타를 저장할 때 least significant byte를 최하위 메모리 주소에 저장하는 방식을 사용합니다. 이러한 시스템을 “little endian”이라 부릅니다. 반면, Solaris를 비롯한 다른 운영체제는 most significant byte를 최하위 메모리 주소에 저장하며, 이러한 시스템을 “big endian”이라 부릅니다. Big-endian 시스템이 little-endian 시스템으로부터 데이타를 읽어 들이려면 변환 프로세스를 거쳐야 합니다. 그렇지 않은 경우, byte order 문제로 데이타가 올바르게 표시되지 않습니다. (Byte order에 대한 상세한 설명은 Embedded Systems Programming 2002년 1월호 기사, "Introduction to Endianness"를 참고하시기 바랍니다.) 하지만 동일한 endian을 갖는 플랫폼 간에 테이블스페이스를 전송하는 경우에는 변환 작업이 필요하지 않습니다.
 
그렇다면 어떤 운영체제가 어떤 byte order를 사용하는지 어떻게 알 수 있을 까요? 아래와 같은 쿼리를 사용하면 바로 확인할 수 있습니다:
SQL> select * from v$transportable_platform order by platform_id;


PLATFORM_ID PLATFORM_NAME                       ENDIAN_FORMAT
----------- ----------------------------------- --------------
          1 Solaris[tm] OE (32-bit)             Big
          2 Solaris[tm] OE (64-bit)             Big
          3 HP-UX (64-bit)                      Big
          4 HP-UX IA (64-bit)                   Big
          5 HP Tru64 UNIX                       Little
          6 AIX-Based Systems (64-bit)          Big
          7 Microsoft Windows IA (32-bit)       Little
          8 Microsoft Windows IA (64-bit)       Little
          9 IBM zSeries Based Linux             Big
         10 Linux IA (32-bit)                   Little
         11 Linux IA (64-bit)                   Little
         12 Microsoft Windows 64-bit for AMD    Little
         13 Linux 64-bit for AMD                Little
         15 HP Open VMS                         Little
         16 Apple Mac OS                        Big
 
인텔 기반 Linux 운영체제를 사용하는 SRC1서버의 USERS 테이블스페이스를, Microsoft Windows 기반 TGT1 서버로 전송하는 경우를 생각해 봅시다. 이 경우 소스 플랫폼과 타겟 플랫폼 모두 little endian type 시스템입니다. USERS 테이블스페이스의 데이타파일은 users_01.dbf입니다. 전송 작업은 아래와 같은 절차를 거쳐 수행됩니다:
  1. 테이블을 READ ONLY 상태로 설정합니다:
    alter tablespace users read only;
  2. 테이블을 익스포트 합니다.. 운영체제 프롬프트에서 다음과 같이 입력합니다:
    exp tablespaces=users transport_tablespace=y file=exp_ts_users.dmp
    exp_ts_users.dmp 파일은 메타데이타만을 포함하고 있으므로 그 크기가 매우 작습니다.
  3. exp_ts_users.dmp 파일과 users_01.dbf 파일을 TGT1 서버로 복사합니다. FTP를 사용하는 경우에는 binary 옵션을 설정합니다.
  4. 데이타베이스에 테이블스페이스를 “플러깅(plugging)” 합니다. 운영체제 프롬프트에서 다음과 같이 입력합니다.
    imp tablespaces=users transport_tablespace=y file=exp_ts_users.dmp datafiles='users_01.dbf'
4번째 단계를 마치고 나면 타겟 데이타베이스에 USERS 테이블스페이스가 생성되며, 테이블스페이스의 컨텐트도 사용 가능한 상태가 됩니다.
 
시스템 SRC1과 TGT1은 각각 Linux, Windows 운영체제를 사용한다는 사실을 명심하시기 바랍니다. 만일 Oracle9i 환경이었다면 TGT1의 데이타베이스가 users_01.dbf 데이타파일을 인식하지 못했을 것이고, 결국 전체 프로세스가 실패로 돌아갔을 것입니다. 이러한 경우라면 일반적인 익스포트/임포트 기능을 이용하거나, 플랫 파일을 생성한 뒤 SQL*Loader로 로드하거나, 데이타베이스 링크를 통해 direct load insert를 실행해야 할 것입니다.
 
10g에서는 타겟 데이타베이스가 다른 플랫폼으로부터 전송된 데이타파일을 정상적으로 인식하므로, 이러한 대안을 고려할 필요가 없습니다. 위의 예에서는 OS의 byte order 역시 동일하므로 (little endian), 변환 작업을 수행할 필요도 없습니다.
 
이 기능은 데이타 웨어하우스의 데이타가, 특수한 목적으로 운영되는 소규모 데이타 마트(data mart)에 정기적으로 전송되는 환경에서 특히 유용합니다. 10g 환경으로 구성된 경우, 데이타 웨어하우스는 대형 엔터프라이즈급 서버에, 데이타 마트는 Linux 기반 인텔 머신과 같은 저가형 서버에 구성하는 것이 가능해집니다. 이처럼 transportable tablespace를 사용하여 다양한 하드웨어와 운영체제를 조합한 환경을 구현할 수 있습니다.
 
서로 다른 endian을 갖는 시스템 간의 데이타 전송
 
소스 플랫폼과 타겟 플랫폼이 서로 다른 endian을 갖는 경우 어떻게 데이타 전송을 처리할 수 있을까요? 앞에서 설명한 것처럼 타겟 서버와 소스 서버의 byte order가 다르면 전송된 데이타를 올바르게 인식할 수 없으므로, 단순 카피 작업으로 데이타 파일을 이동하는 것이 불가능합니다. 하지만 방법은 있습니다. 바로 Oracle 10g RMAN 유틸리티가 데이타파일을 다른 byte order로 변환하는 기능을 지원하고 있습니다.
 
위의 예에서, 만일 SRC1 서버가 Linux(little endian)를 기반으로 하고, TGT1 서버가 HP-UX(big endian)을 기반으로 한다면, 3단계와 4단계의 사이에 변환을 위한 별도의 단계를 적용해야 합니다. RMAN을 사용하면 Linux 환경의 데이타파일을 HP-UX 포맷으로 변환할 수 있습니다 (단 테이블스페이스가 읽기전용 상태로 설정되어 있어야 합니다).
RMAN> convert tablespace users
2> to platform 'HP-UX (64-bit)'
3>  format='/home/oracle/rman_bkups/%N_%f';

Starting backup at 14-MAR-04
using channel ORA_DISK_1
channel ORA_DISK_1: starting datafile conversion
input datafile fno=00004 name=/usr/oradata/dw/starz10/users01.dbf
converted datafile=/home/oracle/rman_bkups/USERS_4
channel ORA_DISK_1: datafile conversion complete, elapsed time: 00:00:07
Finished backup at 14-MAR-04
위 과정을 거치면 /home/oracle/rman_bkups 디렉토리에 표준 RMAN 파일 포맷의 파일이 <tablespace_name>_<absolute_datafile_no> 의 파일명으로 생성됩니다. 결국 USERS 테이블스페이스 자체는 전혀 변경되지 않았고, HP-UX 환경을 위한 새로운 파일이 생성되었습니다. 이제 이 파일을 타겟 시스템으로 복사한 뒤 위에서 설명한 것과 같은 처리 과정을 거치면 됩니다.
RMAN 변환 명령은 매우 강력합니다. 위와 같은 명령을 사용하는 경우, RMAN은 순차적으로 데이타파일을 생성합니다. 여러 개의 데이타파일을 포함하는 테이블스페이스를 처리할 때에는 여러 개의 변환 프로세스를 병렬적으로 수행하도록 명령할 수도 있습니다. 그렇게 하려면 위 명령에 아래 구문을 삽입하면 됩니다:
parallelism = 4
위와 같이 하면 네 개의 RMAN 채널이 생성되어 각각 별도의 데이타파일에 대해 변환 작업을 수행합니다. 하지만 parallelism이 정말로 효과를 발휘하는 것은, 많은 수의 테이블스페이스를 한꺼번에 변환할 때입니다. 아래는 두 개의 테이블스페이스(USERS와 MAINTS)를 HP-UX 포맷으로 변경하는 예입니다:
RMAN> convert tablespace users, maints
2> to platform 'HP-UX (64-bit)'
3> format='/home/oracle/rman_bkups/%N_%f'
4> parallelism = 5;

Starting backup at 14-MAR-04
using target database controlfile instead of recovery catalog
allocated channel: ORA_DISK_1
channel ORA_DISK_1: sid=244 devtype=DISK
allocated channel: ORA_DISK_2
channel ORA_DISK_2: sid=243 devtype=DISK
allocated channel: ORA_DISK_3
channel ORA_DISK_3: sid=245 devtype=DISK
allocated channel: ORA_DISK_4
channel ORA_DISK_4: sid=272 devtype=DISK
allocated channel: ORA_DISK_5
channel ORA_DISK_5: sid=253 devtype=DISK
channel ORA_DISK_1: starting datafile conversion
input datafile fno=00004 name=/usr/oradata/dw10/dw10/users01.dbf
channel ORA_DISK_2: starting datafile conversion
input datafile fno=00005 name=/usr/oradata/dw10/dw10/users02.dbf
channel ORA_DISK_3: starting datafile conversion
input datafile fno=00006 name=/usr/oradata/dw10/dw10/maints01.dbf
channel ORA_DISK_4: starting datafile conversion
input datafile fno=00007 name=/usr/oradata/dw10/dw10/maints02.dbf
converted datafile=/home/oracle/rman_bkups/USERS_4
channel ORA_DISK_1: datafile conversion complete, elapsed time: 00:00:03
converted datafile=/home/oracle/rman_bkups/USERS_5
channel ORA_DISK_2: datafile conversion complete, elapsed time: 00:00:00
converted datafile=/home/oracle/rman_bkups/MAINTS_6
channel ORA_DISK_3: datafile conversion complete, elapsed time: 00:00:01
converted datafile=/home/oracle/rman_bkups/MAINTS_7
channel ORA_DISK_4: datafile conversion complete, elapsed time: 00:00:01
Finished backup at 14-MAR-04
위의 실행결과에서, 변환된 파일이 기존 파일명과 무관하고 이해하기도 어려운 파일명을 갖게 되는 것을 볼 수 있습니다 (예를 들어, users01.dbf는 USERS_4로 변환됩니다). 원하는 경우 데이타파일의 naming format을 변경할 수 있습니다. 이 프로세스는 Data Guard에서 사용하는 데이타파일 naming 방식과 유사합니다:
RMAN> convert tablespace users
2> to platform 'HP-UX (64-bit)'
3> db_file_name_convert '/usr/oradata/dw10/dw10','/home/oracle/rman_bkups'
4> ;

Starting backup at 14-MAR-04
using channel ORA_DISK_1
channel ORA_DISK_1: starting datafile conversion
input datafile fno=00004 name=/usr/oradata/dw10/dw10/users01.dbf
converted datafile=/home/oracle/rman_bkups/users01.dbf
channel ORA_DISK_1: datafile conversion complete, elapsed time: 00:00:03
channel ORA_DISK_1: starting datafile conversion
input datafile fno=00005 name=/usr/oradata/dw10/dw10/users02.dbf
converted datafile=/home/oracle/rman_bkups/users02.dbf
channel ORA_DISK_1: datafile conversion complete, elapsed time: 00:00:01
Finished backup at 14-MAR-04 
 
위와 같이 하면 기존의 파일명을 그대로 유지할 수 있습니다. /home/oracle/rman_bkups 디렉토리에 가 보면, users01.dbf와 users02.dbf가 생성된 것을 확인할 수 있습니다. 위 예제의 경우, 파일의 변환 작업은 소스 플랫폼에서 수행되었습니다. 필요한 경우 타겟 플랫폼에서 변환을 수행할 수도 있습니다. 예를 들어, users01.dbf를 HP-UX 기반의 TGT1 서버로 카피한 후 아래와 같이 HP-UX 포맷으로 변환할 수 있습니다:
In the above cases, we converted the files on the source platform. However, you can do that on the target platform as well. For example, you can copy file users01.dbf to host TGT1 running HP-UX and then convert the file to HP-UX format with:
RMAN> convert
2> datafile '/usr/oradata/dw10/dw10/users01.dbf'
3> format '/home/oracle/rman_bkups/%N_%f'
4> ;
이렇게 함으로써 해당 디렉토리에 지정된 포맷의 파일을 생성할 수 있습니다.
 
그렇다면 데이타파일을 굳이 타겟 플랫폼에서 변환하는 이유가 무엇일까요? 첫 번째로, 소스 플랫폼의 테이블스페이스를 READ ONLY 상태로 두는 기간이 짧아지므로 다운타임을 줄일 수 있다는 점을 들 수 있습니다. 데이타파일을 3중 미러 형태로 구성하고 테이블스페이스를 읽기 전용으로 설정한 다음, 3번째 미러를 분리한 후 곧바로 테이블스페이스를 읽기/쓰기 모드로 변경할 수도 있습니다. 분리된 3번째 미러는 타겟 시스템에 마운트된 후 변환됩니다. 이렇게 하면 테이블스페이스가 읽기 전용 상태에 있는 기간을 최소화할 수 있습니다.
 
또 다른 이유로 성능을 들 수 있습니다. 지속적으로 부하가 발생하는 OLTP 데이타베이스에서 RMAN 변환 작업을 수행함으로써 시스템에 불필요한 부담을 주게 될 수 있습니다. 그 대신, 병렬 작업에 최적화된 데이타 웨어하우스 서버에서 오프라인 형태로 변환 작업을 처리하는 것이 바람직할 수 있습니다.
 
External Table을 데이타 전송 매개체로 활용하기
 
Oracle9i Database에서 처음 소개된 external table은 일정한 형식을 갖춘 일반 텍스트 파일을 테이블처럼 보이게 하고 SQL 구문을 통해 접근할 수 있게 하는 기능입니다. OLTP 데이타베이스에서 운영 중인 TRANS 테이블의 컨텐트를, external table을 사용하여 데이타 웨어하우스 데이타베이스로 이동해야 하는 경우를 생각해 봅시다. 그 과정이 아래와 같습니다:
  1. OLTP 데이타베이스에서, TRANS 테이블의 컨텐트를 포함하는 텍스트 파일을 생성합니다. 생성된 텍스트 파일을 /home/oracle/dump_dir 디렉토리에 trans_flat.txt라는 이름으로 저장합니다. (SQL 구문을 이용하여 텍스트 파일의 생성이 가능합니다.)
    spool trans_flat.txt
    select <column_1> ||','|| <column_2> ||','|| ...
    from trans;
    spool off
  2. ftp, rcp 등의 전송 메커니즘을 사용하여 파일을 데이타 웨어하우스 서버에 복사합니다. (파일은 /home/oracle/dump_dir 디렉토리에 위치하고 있습니다.) 데이타 웨어하우스 데이타베이스에서 dump_dir 디렉토리를 생성합니다:
  3. On the data warehouse database, create a directory object named dump_dir as:
    create directory dump_dir as '/home/oracle/dump_dir';
  4. external table을 생성합니다:
    create table trans_ext
    (
       ... <columns of the table> ...
    )
    organization external
    (
       type oracle_loader
       default directory admin
       access parameters
       (
          records delimited by newline
          badfile 'trans_ext.bad'
          discardfile 'trans_ext.dis'
          logfile 'trans_ext.log'
          fields terminated by ","  optionally enclosed by '"'
          (
              ... <columns> ...
          )
       )
       location ('trans_flat.txt')
    )
    reject limit unlimited;
  5. Direct load insert, merge 등의 일반적인 방법을 사용하여 external table을 일반 테이블로 로드합니다.
위에서 텍스트 파일을 생성하는 첫 번째 단계는 가장 많은 시간을 소요합니다. SQL 구문을 사용하여 텍스트를 생성하고 파일에 스풀링하는 과정은 절차 상으로는 간단하지만 실행 시간이 오래 걸립니다. SQL*Plus 대신 Pro*C 또는 OCI 프로그램을 사용하여 처리 시간을 어느 정도 단축할 수 있지만 그래도 꽤 오랜 시간이 필요합니다. 컬럼을 수작업으로 지정하는 것도 작업을 지체시키는 요인이 됩니다.
 
이 두 가지 문제는 10g에서 완전히 해결되었습니다. 이제 external table 생성 프로세스를 사용하여 테이블을 포터블 포맷으로 신속하게 언로드할 수 있습니다. 위 예의 첫 번째 단계는 아래와 같은 간단한 SQL 구문으로 대치됩니다:
create directory dump_dir as '/home/oracle/dump_dir';

create table trans_dump
organization external
(
   type oracle_datapump
   default directory dump_dir
   location ('trans_dump.dmp')
)
as
select * from trans
/
위 명령은 /home/oracle/dump_dir 디렉토리에 trans_dump.dmp라는 이름의 파일을 생성합니다. 이 파일은 ASCII 텍스트 파일이 아닙니다. 메타데이타는 일반 텍스트이지만, 실제 데이타는 raw 포맷을 사용하고 있습니다. 하지만, 이 파일은 export dump 파일과 마찬가지로 모든 운영체제에서 호환 가능하며, 데이타의 다운로드가 매우 빠르게 수행된다는 점에서 export와 차별화됩니다. 이 파일을 데이타 웨어하우스 서버에 카피하고 위에서 설명한 것과 동일한 방법으로 external table을 생성할 수 있습니다.
 
그렇다면 지금까지 설명한 방법이 기존에 사용되어 오던 데이타 전송 메커니즘과 어떤 차이가 있는 것일까요? 첫 번째로, 복잡한SQL 구문을 작성하지 않고도 포터블 파일을 매우 빠르게 생성할 수 있습니다. 두 번째로, 이 파일을 external table의 input으로 적용해서 일반적인 테이블을 다루듯 다른 테이블로의 데이타 로드 작업을 간단하게 완료할 수 있습니다. 또 아래와 같은 구문을 사용하면 external table로의 데이타 다운로드 성능을 향상시킬 수 있습니다:
create table trans_dump
organization external
(
   type oracle_datapump
   default directory dump_dir
   location ('trans_dump.dmp')
)
parallel 2
as
select * from trans
/
위 명령은 병렬적인 형태로 파일 생성 작업을 수행하도록 합니다. 이 방법은 멀티-CPU 환경에서 유용합니다. 이와 별도로, 동시에 여러 개의 external table을 생성하도록 할 수도 있습니다:
create table trans_dump
organization external
(
   type oracle_datapump
   default directory dump_dir
   location ('trans_dump_1.dmp','trans_dump_2.dmp')
)
parallel 4
as
select * from trans
/
위 명령은 trans_dump_1.dmp와 trans_dump_2.dmp라는 두 개의 파일을 생성합니다. 이 방법은 파일을 여러 개의 물리적 디바이스 또는 컨트롤러로 분산하고 I/O 성능을 향상시키는데 유용합니다.
 
결론
 
10g의 transportable tablespace를 적극적으로 활용함으로써, 분석된 데이타가 더 신속하게, 그리고 더 높은 빈도로 사용자에게 제공되는 환경을 구현할 수 있습니다. 또 이 기능은 오프라인 미디어를 통해 이기종 시스템의 데이타베이스로 데이타를 배포하는 데에도 이용됩니다. External table을 이용한 다운로드 기능은 대용량 데이타 처리를 위한 ETL 툴로써 손색이 없습니다.
 
Furthermore, by making transportable tablespaces viable, 10g makes data refreshes quicker and more frequent so that analyzed data is available to end users sooner. This capability can also be used to publish data via offline media to different databases, regardless of their host systems. Using external table downloads the utility to move large quantities of data as an ETL tool is finally available to the end user.
 
10g의 테이블스페이스 전송 기능에 대한 자세한 설명은 Oracle Database Administrator's Guide의 Chapter 8, "Transporting Tablespaces Between Databases" 섹션을 참고하시기 바랍니다.
 
 
 

 


출처: http://www.oracle.com/technology/global/kr/pub/articles/10gdba/week16_10gdba.html

 

'(DB) Oracle > 기타' 카테고리의 다른 글

Oracle - RMAN  (0) 2017.01.22
Oracle - Flashback_Table  (0) 2017.01.22
Oracle - Top SQL 튜닝하기  (0) 2017.01.22
Oracle - Redo buffer 관련 Wait  (0) 2017.01.22
Oracle - Buffer Cache 관련 Wait  (0) 2017.01.22
Posted by 농부지기
,

[ Oracle - Top SQL 튜닝하기 ]    

 

[6] Top SQL 튜닝하기 (맺음)

 

■ Top SQL 튜닝의 필요성

지난 회까지 실시간 Wait Event 모니터링과 이벤트별 원인분석에 대해서 간단히 살펴보았다. 일시적 성능장애 시 재빨리 원인을 찾아내는 것도 중요하지만 보다 바람직한 것은 이러한 성능문제를 사전에 최대한 예방하는 것임은 두말할 필요도 없다. 오라클 성능문제를 다루는데 있어 강조하고 싶은 한가지는 시스템 자원의 배분을 변경하거나 증가를 고려하기 전에, 불필요한 작업을 최소화함으로써 자원요구 횟수와 자원점유 시간을 줄여주는 노력이 선행되어야 한다는 점이다. Wait Event에 대한 모니터링과 분석이 DBMS의 자원에 대한 경합과 관련된 성능문제를 파악하는데 유용한 방법임에 틀림없지만, 이 같은 정보는 데이터베이스 혹은 그 하위 레벨의 구조적 비효율성을 드러내어줄 뿐 애플리케이션 레벨의 문제를 직접적으로 알려주지는 않는다. 간단히 말하자면, DBMS 튜닝을 위해 정성을 쏟기 이전에 애플리케이션 튜닝에 더 많은 투자를 하라는 것이다. 이런 관점에서 DBA가 비교적 손쉽게 수행할 수 있는 것이 오라클 메모리로부터 악성 SQL을 추출하여 튜닝하는 Top SQL 튜닝이다.

■Top SQL 추출기준

사용자로부터 요청되어 오라클 내에서 처리되는 모든 SQL은 오라클의 공유 메모리 영역 가운데 shared pool내에 캐쉬 되어 지며 이렇게 캐쉬 되어 있는 SQL과 관련 통계정보는 V$SQL 또는 V$SQLAREA 뷰를 통해서 조회할 수 있다. 이때, Top SQL을 추출하는데 중요하게 사용되는 항목은 buffer_gets, disk_reads, executions, rows_processed 등이며 일반적으로 아래와 같은 기준으로 Top SQL을 추출한다.

▷ Buffer gets 수치가 높은 SQL

Buffer gets은 해당 SQL이 처리되는 과정에서 액세스한 메모리 블록의 수(Logical IO)를 의미한다. 물론 이 값이 높다고 해서 무조건 악성 SQL임을 의미하는 것은 아니다. 즉, 이러한 SQL들 중에는 실제로 요구되는 작업량이 많아서 액세스 블록수가 많은 SQL도 있을 것이며 불필요한 처리를 수행하느라 액세스 블록수가 많은 SQL도 있을 것이다. 어느 경우이든 이 SQL들이 현재 오라클 서버에 부하를 많이 유발하고 있는 SQL들이라는 것만은 분명하며 사소한 비효율적 요소에 의해서도 서버에 큰 영향을 미칠 잠재적인 가능성이 있는 SQL들이므로 일차적으로 점검해 볼 필요가 있다.

악성 SQL여부를 판단하기 위한 Buffer gets의 수치에 절대적인 기준은 없으며 시스템의 데이터 규모와 트랜잭션량에 따라 다르다. buffer gets값을 기준으로 역순으로 정렬한 후 패턴을 살펴 적절한 추출기준을 선택하는 것이 좋을 것이다. 만일, 상위 몇 개의 SQL들과 나머지 SQL들 간의 buffer gets의 편차가 매우 크게 나타난다면 상위 몇 개의 SQL에 대해서만 튜닝을 수행해 주어도 큰 효과를 볼 수 있을 것이다. 일반적으로 시스템에서 수행되는 SQL 가운데 심각한 부하를 야기하는 SQL은 소수에 불과한 경우가 많으며 뒤에 기술될 다른 조건들과 조합하여 최대 Top 50건 정도를 추출하여 효율성을 검증하고 튜닝을 통해 개선하는 작업을 수행하여 주면 충분하다.

▷Buffer gets/Execution 수치가 높은 SQL

SQL의 단위 수행당 buffer gets 수치를 의미한다. 단위 수행당 buffer gets 값이 높다는 것은 해당 SQL의 처리가 비효율적일 가능성이 높음을 의미한다. 액세스 블록수가 비정상적으로 많다는 것은 rows_processed 값과 비교하여 상대적으로 평가되어야 할 부분이다. 실제로 반환하는 로우수가 매우 많은 배치성 SQL이거나 혹은 반환되는 로우수가 1건이라도 Group Function이 사용된 Summary성 SQL이라면 처리과정에서 많은 수의 블록을 액세스하는 것은 불가피하며 이 자체가 문제가 될 수는 없기 때문이다.

▷Execution 수치가 높은 SQL

Executions는 해당 SQL이 수행된 횟수를 의미한다. 수행횟수가 잦은 SQL은 buffer gets가 높을 경우가 많다. 일반적으로 십만 ~ 백만 회 이상 빈번하게 수행되는 SQL이라면 buffer gets/executions 값이 2자리 수 이내의 값을 나타내어야 정상이며 단위 수행당 속도는 0.1초 이내로 매우 빨라야 한다. 따라서, 이러한 SQL의 경우 SQL단위로 보면 튜닝의 효과를 체감하기도 어렵고 필요성을 느끼지 못할 수도 있으나 튜닝을 통해 아주 적은 차이라도 개선을 가져올 수 있다면 시스템 전체적인 관점에서는 매우 큰 효과를 가져다 줄 수 있다는 점이 중요하다. 하루에 백만번 수행되는 SQL에 대하여 0.01초를 개선한다면 시스템 시간으로 하루에 일만초를 절약한 셈이 될 것이다. 이러한 SQL에 대해서는 현재 빠르게 수행되고 있다고 해도 더 빠르게 처리할 여지가 없는지 점검하고 가능한 모든 방안을 동원하여 개선시키도록 노력해야 한다.

▷disk_reads 수치가 높은 SQL

disk_reads는 SQL이 처리되는 과정에서 물리적인 IO를 통해 액세스한 블록의 수를 의미한다. 물리적 IO의 발생여부는 원하는 블록이 메모리에 캐쉬되어 있는지 여부에 따라 달라지므로 수행되는 횟수와 수행되는 시간대의 데이터베이스 캐쉬 상황에 따라 유동적이라고 할 수 있다. 그러나, buffer gets의 값과 비교하여 disk_reads의 비율이 높은 SQL은 Full Scan을 수행하는 SQL일 가능성이 큰데 그 이유는 Full Scan을 통해 액세스되는 블록들은 기본적으로 DB buffer Cache의 LRU 알고리즘에 의해 관리되지 않으므로 작업 후에 곧바로 메모리로부터 밀려나 버릴 가능성이 높기 때문이다. 반면에 인덱스를 통하여 액세스하는 경우, 일상적으로 액세스되는 테이블에 대해서는 인덱스의 root block과 branch block은 항상 메모리에 캐쉬 되어 있을 확률이 높으므로 물리적 IO를 유발하는 비율이 낮을 수 밖에 없다.

■Top SQL 추출기준

글을 맺기 전에 마지막으로 언급하고 싶은 것 하나는, 문제가 발생했을 때 문제의 원인이 bug로 인한 것일 가능성을 항상 염두에 두어야 헛된 고생을 덜한다는 것이다. 오라클도 사람이 만든 프로그램이므로 버그가 없을 수 없으나 다행히 오라클의 버그 및 패치 관리는 매우 훌륭한 편이다. 오라클 메타링크를 활용하여 유사한 문제가 보고된 적은 없는지 관련 버그에 대한 정보는 없는지 살펴보아야 하며, 평소에 정기적으로 패치 및 버전 관리를 해주는 것이 바람직하다.

오라클 시스템을 운영하다 보면 현실에서는 다양한 문제가 복잡하게 얽혀 나타나므로 명백한 원인을 파악하기가 쉽지 않을 때가 많지만, 운영 시 자신의 시스템에서 자주 발생하는 Wait 패턴 또한 분명히 존재하므로 굵은 가지들부터 하나씩 이해하고 해결해 나가다 보면 오라클이 우리가 보인 애정에 보답해줄 날이 올 것이라 믿는다. 지면 관계상 OPS(RAC) 관련 Wait을 비롯한 기타 Wait 이벤트에 대해 다루지 못한 점, 그리고 각 Wait 이벤트별로 좀더 친절한 설명과 사례를 제시하지 못한 점이 아쉬움으로 남지만, 누구든 아주 작은 것 하나라도 이 글을 통해 새로이 얻을 수 있었다면 그 이상 바랄 것은 없다.


출처: http://www.oracle.com/technology/global/kr/pub/columns/dbtuning04.html

'(DB) Oracle > 기타' 카테고리의 다른 글

Oracle - Flashback_Table  (0) 2017.01.22
Oracle - Transportable Tablespaces  (0) 2017.01.22
Oracle - Redo buffer 관련 Wait  (0) 2017.01.22
Oracle - Buffer Cache 관련 Wait  (0) 2017.01.22
Oracle - Shared Pool 관련 Wait  (0) 2017.01.22
Posted by 농부지기
,

[ Oracle - Redo buffer 관련 Wait ]     

 

[5] Redo buffer 관련 Wait

  ■ Redo buffer 구조

오라클 리두 구조의 핵심은 모든 트랜잭션 정보를 OS 파일에 기록해 둠으로써 시스템 장애가 발생해도 트랜잭션 단위의 일관성을 잃지 않고 데이터베이스를 복구할 수 있도록 하겠다는 것이다. 리두버퍼(redo buffer)는 이처럼 데이터베이스에 가해진 모든 변경내역을 파일에 기록 하기 위해 잠시 사용되는 메모리 영역이며 리두버퍼에 기록된 리두 정보는 다시 리두로그 파일에 기록되어짐으로써 향후 시스템 복구 작업이 필요할 때에 사용하게 된다. 오라클의 리두 구조를 이해하기 위한 핵심적인 개념을 간단히 정리해보면 다음과 같다.

데이터베이스에 대한 변경내역은 블록단위로 저장된다. 물론 변경되는 모든 블록의 복사본을 통째로 저장하는 것은 아니고 블록별로 어떠한 오퍼레이션을 수행하는가, 그리고 그러한 블록별 오퍼레이션을 어떠한 순서로 수행하는가를 기록한다. 이러한 블록별 단위액션을 change vector라고 부르며 change vector가 순차적으로 모여 하나의 의미 있는 redo record가 된다. 리두로그는 시스템내의 모든 프로세스들에 의해 생성되는 redo record를 SCN 순서대로 저장해놓은 것이다. 이때 리두로그에 기록되는 내용에는 테이블이나 인덱스 등의 데이터 블록 뿐만 아니라 UNDO 블록 또는 UNDO 세그먼트 헤더블록에 대한 변경내용을 포함하는 모든 버퍼캐쉬 블록에 대한 변경내역이 대상이 된다.

리두 정보는 항상 실제 변경작업보다 먼저 보관되어야 어떤 상황에서도 복구가 가능해진다. 따라서 트랜잭션을 수행하는(데이터베이스 블록에 변경을 가하는) 프로세스는 우선 자신의 메모리 영역 내에서 수행하고자 하는 작업에 대한 리두 레코드를 만들며, 이를 먼저 로그버퍼에 기록하고 난 후에 실제 버퍼블록에도 리두 레코드에 담긴 내용을 따라 적용하게 된다. 또한 같은 이유로 오라클은 변경된 버퍼캐쉬 블록을 디스크에 기록하기 전에 먼저 관련된 로그버퍼를 로그파일에 기록하는 작업을 처리하게 된다. 따라서, 리두 버퍼 또는 리두 파일 (아카이브 파일을 포함해서)에 대한 쓰기 작업에 병목이 생기면 시스템에 대한 모든 작업 수행이 대기 상태로 빠지게 될 것이다.

트랜잭션 커밋을 요청한 프로세스는 우선 해당 트랜잭션에 대한 로그버퍼가 리두로그 파일에 기록되는 작업이 완료된 후에야 커밋 완료 메세지를 받을 수 있다. 그렇게 함으로써 버퍼캐쉬 변경내역을 모두 디스크에 반영하지 않고도 시스템의 비정상 종료시 리두파일에 저장된 리두 레코드로부터 커밋 트랜잭션을 보존할 수 있게 된다.

■리두 버퍼관련 Wait 이벤트

일반적으로는 로그버퍼 관련해서 심각한 Waiting이 발생하는 경우는 드물지만, 가끔 볼 수 있는 리두 관련 Wait 이벤트로는 다음과 같은 것들이 있다.

▷ Log file parallel write

LGWR가 OS에 리두 버퍼를 로그파일에 기록하도록 요청해 둔 상태에서 대기하고 있는 이벤트이다. 이 경우에는 DML 작업시 nologging 옵션 등을 사용하여 시스템에서 발생하는 리두 레코드의 절대량을 줄이거나 하드웨어적으로 DISK IO를 개선시켜주는 것이 방안이다.

▷Log buffer space

프로세스가 로그버퍼를 할당하기 위해 대기하는 이벤트인데 LGWR가 로그버퍼를 비우는 것보다 더 빠른 속도로 프로세스들이 리두 레코드를 생성하고 있다는 것을 의미한다. 로그버퍼의 크기를 늘려주거나, DISK IO의 속도를 개선시켜 주어야 할 것이다. 로그버퍼는 로그파일에 대응되는 블록이 맵핑이 된 후에 사용될 수 있으므로 로그 스위치 발생시에도 log buffer space 이벤트에 대한 대기가 발생할 수 있다. 로그 스위치가 너무 잦다면 리두 로그 파일의 크기를 증가시켜주는 것이 좋다.

▷ Log file sync

프로세스가 커밋이나 롤백을 수행할 경우 우선 LGWR에게 해당 트랜잭션까지의 로그버퍼를 Write하도록 요청하게 되는데 이때 사용자 프로세스는 LGWR가 쓰기 작업을 완료할 때까지 log file sync 이벤트를 대기하게 된다. 버전 8i 이전에서는 DBWR가 쓰기 작업을 수행하다가 아직 관련 로그버퍼가 파일에 쓰여지지 않을 경우에도 LGWR에 쓰기를 요청하고 log file sync 이벤트에 대기하였으나 8i 이상에서는 log file sync에 대기하는 대신 deferred write queue에 등록한다. 따라서 버전 8i 이상에서 log file sync 이벤트는 사용자 프로세스에 의해 요청되는 커밋, 롤백 처리 시에 발생하며 결국, 시스템 전체적으로 커밋, 롤백이 지나치게 자주 수행되거나 상대적으로 LGWR의 쓰기 속도가 느린 것이 원인일 것이다. 또는, 로그 버퍼가 너무 커서 LGWR가 백그라운드로 flush 시켜주기 전( 보통 3초 간격 및 1/3 이상의 로그버퍼가 찬 경우)에 커밋에 의한 쓰기 요청이 이루어지므로 커밋 시점에 써야 할 양이 많아 대기시간이 길어지는 경우도 있는데 이 경우엔 리두 버퍼의 크기를 오히려 줄여주어야 할 것이다. 또는, LGWR wait for redo copy 이벤트가 많이 나타난다면 redo copy latch가 너무 많아 LGWR이 사용자 프로세스가 버퍼 쓰기 작업을 마칠 때까지 기다리는 일이 잦은 경우를 뜻하며 이 경우엔 _LOG_SIMULTANEOUS_COPIES 파라미터를 사용하여 copy latch의 수를 줄여주는 조치가 필요할 것이다.
시스템에 따라서 언급한 외의 다양한 이벤트 대기와 원인이 존재할 수 있고, 더구나 버전에 따라 redo copy latch와 redo allocation latch를 포함한 리두 운영 방식상 상이한 부분이 많이 존재하여 그에 따른 추가적인 튜닝요소가 있으나 이 글에서는 지면 관계상 8i를 기준으로 간략히 정리해 보았다.

출처: http://www.oracle.com/technology/global/kr/pub/columns/dbtuning04.html

 

'(DB) Oracle > 기타' 카테고리의 다른 글

Oracle - Transportable Tablespaces  (0) 2017.01.22
Oracle - Top SQL 튜닝하기  (0) 2017.01.22
Oracle - Buffer Cache 관련 Wait  (0) 2017.01.22
Oracle - Shared Pool 관련 Wait  (0) 2017.01.22
Oracle - Enqueue와 Latch 개념 이해하기  (0) 2017.01.22
Posted by 농부지기
,

[ Oracle - Buffer Cache 관련 Wait ]     

 

[4] Buffer Cache 관련 Wait

 

■ Buffer Cache 구조

Buffer Cache의 기본적인 기능은 여러 프로세스에 의해 공통으로 자주 액세스 되는 데이터베이스 블록을 메모리에 캐쉬하여 물리적인 디스크 IO를 최소화함으로써 더 빠른 액세스 속도를 제공하기 위한 것이다. 복잡한 설명은 생략하고, Buffer Cache 의 기본구조를 이해하기 위한 몇 가지 핵심 용어들을 간단히 정리해 보도록 하겠다.

▷ Buffer header

모든 버퍼 블록들은 각자의 buffer header를 통해 액세스되고 관리된다. 즉, 메모리에 캐쉬된 특정 데이터 블록에 대한 액세스는 먼저 해쉬 알고리즘을 통해 cache chain 상의 buffer header를 찾고 해당 buffer header에 기록된 데이터 블록의 메모리상 주소를 찾아가 원하는 정보를 읽는 방식으로 이루어진다. Buffer header에 기록되는 주요정보는 다음과 같으며 Buffer header의 내용은 V$bh 뷰를 통하여 조회해볼 수 있다.

     - 메모리상에서의 해당 버퍼블록의 주소
     - 해당 버퍼 블록(실제로는 버퍼헤더)가 포함되어 있는 hash chain
     - LRU, LRUW, CKPTQ와 같은 리스트상에서의 해당 버퍼블록의 위치
     - 해당 버퍼블록에 대한 User, Waiter와 상태를 나타내는 각종 Flag

▷ Hash Buckets/ Hash Chains

Buffer Cache의 모든 블록은 해쉬 알고리즘을 통해 관리된다. 곧, 데이터 블록의 DBA, Class 값으로 Hash Function을 적용하여 해당 블록이 속하는 hash buckets을 할당하며, 동일한 hash buckets에 할당되는 데이터 블록의 버퍼헤더들은 linked list형태로 hash chain을 이루게 된다. Hash buckets/hash chains는 특정 데이터 블록을 찾아가기 위한 수단을 제공한다. 각각의 hash buckets에는 자신에 속한 hash chain을 보호하기 위한 latch(cache buffers chains)가 할당된다.

▷ LRU

LRU는 두개의 리스트, 즉 LRUW와 LRU 리스트의 쌍으로 구성된다. LRUW(LRU Write list)는 dirty list와 같은 말이며, 수정되어 디스크에 반영되어야 할 블록들의 리스트이다. LRU(Least recently used list)는 LRUW에 올라가지 않은 나머지 버퍼 블록들이 등록되어 있다. Buffer cache 상의 버퍼블록은 반드시 LRU나 LRUW 둘 중의 하나에 등록되며, 두 리스트에 동시에 포함되는 경우는 없다. LRU는 Free Buffer를 찾기 위한 수단을 제공한다. 경합을 피하기 위해 버퍼캐쉬 블록들을 여러 개의 LRU쌍으로 나누어 관리할 수 있으며, 각 LRU리스트를 보호하기 위해 Latch(Cache buffers lru chain)가 하나씩 할당된다.

■ Buffer Cache 운영규칙

▷ 메모리상의 특정 버퍼블록을 찾아가거나, 특정 블록이 메모리에 캐쉬 되어 있는지를 확인하기 위해서 오라클은 hash bucket/hash chain 구조를 사용한다.

▷새로운 데이터블록을 디스크로부터 메모리로 읽어 들이기 위한 free buffer를 확보하기 위해 오라클은 LRU 리스트를 사용한다.

▷ 버퍼블록은 LRU나 LRUW 둘 가운데 하나에 등록된다.

▷ 하나의 블록에 대해 시간대가 다른 여러 개의 복사본이 존재할 수 있으며, 그 가운데 오직 CURRENT 버퍼만이 변경될 수 있다.

▷하나의 버퍼블록은 한번에 오직 하나의 프로세스에 의해서만 변경될 수 있다.

■ Buffer Cache 관련 Waits

버퍼캐쉬와 관련되어 흔히 발생하는 대표적인 Wait 이벤트는 다음과 같다.

▷ buffer busy waits

여러 세션이 동시에 같은 블록을 읽으려고 하거나 여러 세션이 같은 블록에 대한 변경작업이 완료되기를 기다리고 있는 경우에 발생하며, 특정 블록에 대한 경합을 해소하기 위한 조치는 블록의 유형에 따라 달라진다. Data block에 대한 경합이 많은 경우는 Pct free나 Pct used 값을 사용하여 블록 당 로우수를 줄이거나, 특정 블록에 로우 입력이 몰리는 구조의 인덱스(right-hand-index)일 경우는 reverse key index의 사용을 검토하는 등의 방법이 있으며, segment header의 경합이 많은 경우는 freelist 수를 늘리거나 Extent의 크기를 증가시키는 등의 방법이 있고, undo header나 undo block에 대한 경합은 롤백세그먼트의 개수나 크기를 증가시키는 것이 전형적인 조치 방법이다. v$waitstat과 x$kcbfwait을 이용하며 Class 또는 file별로 wait 발생상황을 판단할 수 있다.

▷ free buffer waits/write complete waits

DBWR가 dirty buffer를 write하는 동안 서버 프로세스가 대기하고 있는 경우 발생한다. 곧, 너무나 많은 dirty buffer가 생겨나거나 DBWR의 쓰기 속도가 충분히 튜닝 되지 못한 경우에 발생한다. 점검 포인트는 물리적 디스크의 속성(stripe size, layour, cache size) 최적화, Raw device의 활용, Async IO나 multi-DBWR(db_writer_processes) 활용여부 등이다.

위와 같은 버퍼 블록에 대한 경합 역시 비효율적인 실행계획을 통해 수행되는 애플리케이션에 의하여 불필요하게 많은 블록이 메모리로 올라오는 것이 원인일 경우가 많으므로 경합이 빈번한 블록이 속하는 테이블/인덱스 명을 찾아낼 수 있다면 관련 SQL을 찾아내어 보다 효과적인 튜닝작업이 이루어질 수 있을 것이다. v$session_wait의 p1,p2 컬럼에 각각 file#, block#값을 표시하여 주므로 이 값을 이용하여 아래의 SQL문으로 현재 어떤 오브젝트에 대하여 해당 wait가 발생하고 있는지를 추적할 수 있다. ( 1회에 소개한 SQL문에서는 Additional Info 값을 참조. )

     select segment_name, segment_type
     from dba_extents
     where file_id = :file#
     and :block# between block_id and block_id + blocks -1

▷ cache buffers chains latch

SGA내에 캐쉬된 데이터블록을 검색할 때 사용된다. 버퍼캐쉬는 블록들의 chain을 이루고 있으므로 각각의 chain은 이 Latch의 child들에 의해 보호된다. 이 Latch에 대한 경합은 특정 블록에 대한 대량의 동시 액세스가 발생할 때 유발된다. 애플리케이션을 검토해 보아야 한다.
Ø cache buffers lru chain latch
버퍼캐쉬의 버퍼를 LRU 정책에 따라 이동시켜야 할 필요가 있는 경우 프로세스는 이 Latch 획득하게 된다. 이 Latch에 대한 경합은 Multiple buffer pool을 사용하거나 DB_BLOCK_LRU_LATCHES 를 증가시켜 LRU Latch의 개수를 늘려서 해소할 수 있다. SQL문을 튜닝하면 해당 프로세스에 의해 액세스 될 블록의 수가 줄어들 것이므로 당연히 효과를 거둘 수 있다.
위와 같이 버퍼캐쉬를 관리하는 Latch에 대한 경합은 경합이 집중되는 특정 Child Latch에 의해 관리되는 버퍼블록을 찾아 해당 블록이 속한 세그먼트 정보를 알아낸다면 보다 효과적인 조치가 가능할 것인데, latch free wait일 경우 v$session_wait의 p1raw 값이 해당 Latch address를 의미한다. 이 값을 x$bh의 hladdr 값과 조인하면 관련 오브젝트 이름을 추적해볼 수 있다.

     select file#, dbarfil, dbablk, obj, o.name
     from x$bh bh, obj$ o
     where bh.hladdr = :latch_address
     and bh.obj = o.obj#;

 

출처: http://www.oracle.com/technology/global/kr/pub/columns/dbtuning04.html

 

'(DB) Oracle > 기타' 카테고리의 다른 글

Oracle - Top SQL 튜닝하기  (0) 2017.01.22
Oracle - Redo buffer 관련 Wait  (0) 2017.01.22
Oracle - Shared Pool 관련 Wait  (0) 2017.01.22
Oracle - Enqueue와 Latch 개념 이해하기  (0) 2017.01.22
Oracle - Wait Event 모니터링  (0) 2017.01.22
Posted by 농부지기
,

[ Oracle - Shared Pool 관련 Wait ]     

 

[3] Shared Pool 관련 Wait

  ■Share pool과 성능문제

오라클이 공유 메모리(SGA)를 사용하는 가장 큰 이유는 기본적으로 메모리 사용을 최소화하면서 처리성능은 최대화하기 위한 것이다. 한번 액세스된 블록을 Database buffer cache에 캐쉬 함으로써 비용이 큰 Disk I/O를 최소화하는 것처럼, 한번 처리된 SQL의 실행 정보를 Shared Pool에 공유함으로써 파싱 작업을 위한 CPU, 메모리 자원의 사용을 최소화하고 SQL 수행속도를 증가시킬 수 있다. Shared Pool에는 SQL이나 PL/SQL을 수행하기 위한 각종 정보 - SQL구문 및 실행계획, PL/SQL 소스, 테이블, 뷰 등의 각종 오브젝트와 오브젝트 상호간의 의존관계, 권한관계 등 - 가 저장되어 있다. 지면 관계상 이 글에서 Shared Pool의 관리 메커니즘을 상세히 기술할 수는 없지만 몇 가지 내재적인 특징으로 인해 Shared Pool은 오라클의 메모리 영역 가운데에서도 가장 성능문제의 요소가 많은 곳이면서도 효과적인 튜닝이 수월치 않은 영역이기도 하다.

무엇보다, Shared Pool에서 가장 문제가 되는 것은 메모리의 조각화(Fragmentation)이다. Shared Pool에서 라이브러리 캐쉬 오브젝트를 위해 할당되는 메모리 단위를 chunk라고 부르는데 chunk의 크기는 수 바이트에서 수 K바이트에 이르기까지 필요에 의해 다양하게 할당된다. 새로운 chunk의 할당이 필요하게 되면, 프로세스는 이미 존재하는 chunk로부터 필요한 만큼의 크기만을 떼어내어 사용하므로 시간이 흐를수록 점차 메모리가 조각화 되는 것을 피할 수 없다. ( 이는, Pctincrease가 0가 아닌 테이블스페이스에서 익스텐트의 할당과 해제가 반복됨에 따라 공간의 조각화가 심해지는 것을 떠올리면 이해가 쉬울 것이다. ). 어느 정도 정형화된 패턴의 애플리케이션이 수행되는 환경이 아니라, 공유가 불가능한 다양한 형태의 SQL(대표적으로 Literal SQL)이 빈번히 요청되는 환경이라면 Shared Pool 메모리 조각화에 따른 문제는 더욱 심각해진다.

또한, Shared Pool은 일반적인 메모리 캐쉬와는 달리 메모리에 저장되었던 정보를 잠시 기록해둘 대응되는 디스크 공간이 없으므로 한번 flush된 라이브러리 캐쉬 오브젝트를 reload하기 위해서는 해당 정보를 재생성 해야만 한다. 이 과정에서 관련 오브젝트 정보의 검색 및 참조, locking, 메모리 할당 등의 작업을 위해 많은 비용이 들기 때문에 결국 Shared Pool 관련 튜닝의 최대 과제는 SQL 공유를 최대화하여 새로운 파싱 요청과 메모리 요청을 최소화하는 것이라고 할 수 있다. 헌데, 이는 애플리케이션의 설계와 연계되는 영역으로서 이미 개발이 완료된 운영서버에서는 변경작업이 여의치 않은 것이 현실이다. 앞서, Shared Pool이 DBA로서 튜닝이 수월치 않은 영역이라고 표현한 이유 가운데 하나가 여기에 있다.

■ Shared Pool 관련 오해 바로잡기

Shared Pool과 관련하여 판단이 쉽지 않은 부분 가운데 하나가 과연 shared_pool_size를 얼마나 할당할 것인가 하는 것이다. 오라클은 Shared Pool 메모리를 최대한 효율적으로 활용하기 위하여 다양한 기법을 동원하고 있는데, 이러한 메모리 관리 메커니즘에 대해 정확히 알지 못하여 Shared Pool 크기를 지나치게 크게 할당함으로써 오히려 문제를 악화시키는 경우도 드물지 않다. 이러한 오해를 바로잡기 위해 Shared Pool의 메모리 할당과정을 간단하게나마 살펴보도록 하겠다.

새로운 메모리 Chunk가 할당되는 과정을 살펴보면, 우선 프로세스는 Free List를 검색하여 자신이 필요로 하는 크기의 Free Chunk를 찾고, 그러한 Free Chunk가 없으면 원하는 크기보다 한단계 큰 Free Chunk를 찾아서 필요한 크기만큼 분할하여 사용하게 된다. 만약 Free List에서 충분한 크기의 Free Chunk를 찾을 수 없다면, 이미 사용되었으나 현재는 사용되고 있지 않는(unpinned) Chunk들의 LRU List를 검색하여 오래된 것부터 8개씩 flush시켜 Free Chunk로 만든 후 자신이 필요한 크기를 할당하여 사용하게 된다. 만약 이 과정에서 현재 사용중인(pinned) Chunk가 대부분이거나, 너무 메모리 조각화가 많이 일어나서 기존 Chunk를 Flush시킨 후 인접한 Free Chunk들을 병합해보아도 원하는 크기의 Free Chunk를 얻어낼 수 없다면 오라클은 ORA-4031 에러를 발생시키는데, 그 이전에 한가지 최후의 비밀무기가 더 숨어 있다. 바로 Spare Free 메모리라는 것인데 오라클은 인스턴스 기동 후 처음에는 전체 Shared Pool의 50% 가량은 Free List에 올려놓지 않고 아예 숨겨두었다가 앞서와 같이 도저히 피할 수 없는 순간이 되면 조금씩 해제 시켜 사용하도록 한다. 그야말로 메모리의 조각화를 최소화하기 위한 오라클의 눈물 나는 노력이라고 할 수 있을 것이다. 물론 이 영역까지 다 소모한 후에 flush를 통해서도 필요한 Chunk를 확보할 수 없는 상황이 되면 결국 ORA-4031 에러가 발생할 것이다.

많은 이들이 Shared Pool의 남아있는 Free memory의 크기가 작으면 shared_pool_size를 증가시켜주어야 한다고 믿고 있는데 이는 잘못된 것이다. Shared Pool은 정보의 재사용을 위해 운영하는 것이므로 SQL 실행이 끝났다고 해서 해당 Chunk를 Free List로 반납하지 않는다. 즉, Free Memory가 남아있는 한 계속 소모 시키는 방식으로 사용되므로 오랜 시간동안 운영되어온 시스템에서 Shared Pool의 Free Memory가 매우 적게 남아 있는 것은 그 자체로는 문제가 되지 않으며, 오히려 피크타임이 지난 후에도 많은 양의 Free Memory가 남아있다면 이는 Spare Free 메모리도 다 소모하지 않은 상태로서 불필요하게 많은 메모리가 할당되어 낭비되고 있음을 의미한다. 더구나, Shared Pool 크기가 지나치게 크면 Free Memory를 다 사용할 때까지의 기간이 연장되는 효과는 얻을 수 있겠지만, 시간이 지날수록 Memory의 조각화가 더욱 심해지고 Free List의 길이가 길어져 Free Chunk의 검색과 할당에 걸리는 시간이 지연되므로 오히려 성능이 악화되는 결과를 초래할 것이다.

또한, 메모리 조각화에 따른 영향을 줄이기 위해 오라클은 5000 bytes가 넘는 큰 사이즈의 Chunk만을 위해 전체 Shared Pool의 5% 정도를 따로 관리하는 방법을 사용하고 있는데, 경험적으로 보면 이 공간은 거의 사용되지 않고 버려지고 있는 경우가 많다. 이는 V$SHARED_POOL_RESERVED 뷰의 USED_SPACE 값을 확인해 보면 알 수 있으며, 5000 bytes 이상의 large chunk가 거의 요구되지 않는 환경에서는 오히려 이 크기를 줄여주는 것이 나을 것이다.


■Shared Pool 관련 wait

Shared Pool과 관련하여 흔히 발생하는 Wait은 라이브러리 캐쉬 오브젝트에 대한 동시 액세스와 메모리 할당에 따른 관련 Lock 또는 Latch에 대한 경합이 대부분이며, 구체적인 이름은 다음과 같다. (Latch free 이벤트시 괄호 안의 관련 latch 이름은 v$session_wait의 p2값과 v$latchname의 latch#를 조인하여 얻어낼 수 있다. 1회 SQL 참조)

Latch
Lock
latch free ( library cache )
latch free ( library cache load lock)
library cache lock, library cache pin
library cache load lock
latch free ( row cache objects )
row cache lock
latch free ( shared pool )
 

Library cache lock, library cache pin, library load lock은 각각 특정 라이브러리 캐쉬 오브젝트에 대한 검색이나 변경 및 실행 또는 로드 시에 대상 오브젝트에 대해 할당되며, 이러한 Locking 작업은 library cache latch와 library cache load lock latch의 관할 하에 처리된다. Shared pool latch는 Free List나 LRU List를 검색하거나 메모리를 할당하는 작업에 사용되며, row cache lock과 row cache objects latch는 Data dictionary cache 오브젝트에 대한 동시 액세스를 제어하는데 사용된다.

Latch의 개수는 시스템 전체적으로 하나 또는 제한된 개수가 존재하는 것이고 Lock은 대상 오브젝트 각각 대해 할당되는 것이므로, 엄밀하게 말해서 Lock에 대한 경합은 직접적으로는 특정 라이브러리 캐쉬 오브젝트에 대한 동시 액세스로 인해 유발되는 것인 반면에, Latch에 대한 경합은 시스템 전체적으로 관련 오퍼레이션(즉, SQL 파싱) 자체가 지나치게 많이 발생하거나, 짧은 시간 내에 처리되지 못함으로 인해 유발되는 것이라고 구분해볼 수 있다. 그러나, 결국 이 모든 경합은 근본적으로 Shared Pool의 조각화(Fragmentation)에 따른 문제가 주된 원인이며 다시 이러한 조각화는 요청되는 SQL들이 공유되지 못하고 지속적으로 새롭게 파싱되고 메모리가 할당됨으로 인해 발생하는 것이다. 따라서, 이러한 문제를 해결하는 가장 효과적인 방법은 Literal SQL을 바인드 변수를 사용하도록 수정하거나, SQL작성 표준을 마련하고, HOLD_CURSOR/ RELEASE_CURSOR, SESSION_CACHED_CURSORS, CURSOR_SPACE_FOR_TIME, CURSOR_SHARING 등의 파라미터를 활용하는 등의 방법을 통해 SQL의 공유도를 높여주는 것이며, 또한 자주 사용되는 PL/SQL에 대해서는 DBMS_SHARED_POOL 패키지를 사용하여 메모리에서 Flush되지 않도록 보존하는 등의 조치를 취해주면 도움이 될 것이다. SQL의 수정이 어려운 환경이거나 시스템에 요청되는 SQL의 절대량이 확보된 메모리 공간에 비해 많은 상황이라면 주기적으로 피크타임을 피해 Shared Pool을 직접 Flush(alter system flush shared_pool 명령을 사용한다.) 시켜주는 것도 권장할 만한 관리 방법이다. 많은 이들이 우려하는 바와는 달리 Shared Pool을 직접 flush 시키는 것이 심각한 성능상 문제를 야기하지는 않으며 특히 중요한 패키지나 SQL cursor, Sequence 등이 keep되어 있는 경우라면 더욱 그러하다.

가끔 버그를 포함한 특수한 상황에서 특정 라이브러리 캐쉬 오브젝트에 대한 lock이 장시간 해제되지 못하고 있는 경우도 있는데 이때는 X$KGLLK 뷰를 조회하면 library cache lock에 대한 holder/waiter를 확인하여 조치할 수 있다. 또한, Row cache lock에 대한 경합은 Locally managed tablespace를 도입하거나, DML이 빈번한 테이블에 대한 인덱스의 개수를 줄여주는 등의 조치를 통해 완화될 수 있을 것이다.

부연하자면, Shared Pool과 관련된 Wait는 특정 오브젝트 자원에 대한 경합에 의해 발생하기 보다는 애플리케이션의 설계, 보다 단순화시켜 표현하면 Literal SQL에 의한 메모리 조각화에 의해 발생하는 경우가 많다. 따라서, Shared Pool관련 Wait가 많이 발생하여 오라클이 그로 인한 성능상의 문제를 드러낼 때 눈에 띄는 하나의 주범을 찾아내려는 노력은 별 효과를 거두지 못하는 경우가 많으며, 그러한 시점에 DBA가 즉각적으로 취할 수 있는 조치로는 직접 Shared Pool을 Flush 시키는 정도가 있을 것이다. 결국, 평소에 꾸준한 모니터링을 통해 Shared Pool의 적절한 크기와 관련 파라미터 값을 찾아가는 것, 그리고 무엇보다 애플리케이션 측면에서 튜닝 및 수정 작업을 진행함으로써 성능문제를 사전에 예방하는 것이 최선이다.

출처: http://www.oracle.com/technology/global/kr/pub/columns/dbtuning04.html

 

'(DB) Oracle > 기타' 카테고리의 다른 글

Oracle - Top SQL 튜닝하기  (0) 2017.01.22
Oracle - Redo buffer 관련 Wait  (0) 2017.01.22
Oracle - Buffer Cache 관련 Wait  (0) 2017.01.22
Oracle - Enqueue와 Latch 개념 이해하기  (0) 2017.01.22
Oracle - Wait Event 모니터링  (0) 2017.01.22
Posted by 농부지기
,

[ Oracle - Enqueue와 Latch 개념 이해하기 ]     

 

[2] Enqueue와 Latch 개념 이해하기

 

DBMS의 가장 주된 기능 중에 하나는 동일 자원에 대한 동시 액세스를 관리하는 것이며, 이를 위해 오라클이 사용하는 대표적인 제어 구조가 Enqueue와 Latch이다.
Enqueue와 Latch는 모두 특정 자원에 대한 접근을 serialize하는 것이 목적이라는 점에서는 같은 Lock의 일종이지만 관리방식이나 용도에서 차이가 있다. Enqueue는 이름에서 보듯 Queue를 통해 관리된다. 대상 자원에 대한 Owner, Waiter, Converter Queue를 관리하면서 먼저 요청한 순서대로 Lock을 획득하도록 하는 구조이며, Exclusive 모드 뿐 아니라 다양한 수준의 공유를 허용한다. 대표적인 것이 테이블 데이터를 Update할 때 사용되는 TM, TX enqueue이다.

반면에, Latch는 Enqueue에 비해 훨씬 단순한 구조로서 매우 짧은 시간 내에 획득되고 해제된다. Queue를 통해 관리되지 않으므로 먼저 Request한 프로세스가 먼저 latch를 획득한다는 보장이 없으며, 대부분의 경우 Exclusive모드로만 획득된다. Latch는 주로 SGA의 특정 메모리 구조체에 대한 액세스(library cache latch, cache buffers chains latch) 혹은 메모리 할당 시 (shared pool latch) 사용되거나 오라클의 중요한 코드가 동시에 수행되지 않도록 하기 위한 용도로(redo writing latch) 사용된다. Latch는 Enqueue보다는 하위 level에서 Locking 자체의 부하를 최소화하며 작동하는 제어 메커니즘이라고 할 수 있으며, 실제로 Enqueue 역시 내부적으로는 Latch (enqueues, enqueue hash chains latch )에 의해 운영된다는 점을 생각하면 둘 사이의 차이를 쉽게 이해할 수 있을 것이다.

■ Enqueue

Enqueue 정보는 내부적으로 Enqueue Resource 배열과 Enqueue Lock 배열에 저장된다. 특정 자원에 대한 Lock이 요청되면 대상을 하나의 Resource로 정의하여 할당하고 그 Resource에 대해 관련 Lock 정보를 Owner, Waiter, Converter가운데 하나로서 Link시키는 방식으로 운영되며, 이러한 정보는 V$RESOURCE와 V$LOCK 뷰를 통해 조회해 볼 수 있다. V$RESOURCE와 V$LOCK은 1:M 관계로 하나의 Resource에 대하여 여러 건의 Lock 레코드가 Owner (LMODE>0, REQUEST=0), Waiter (LMODE=0 ,REQUEST>0), Converter (LMODE>0, REQUEST>0) 중 하나로서 대응된다.
Enqueue Wait이 발생하는 것은 다른 세션이 이미 나보다 먼저 해당 자원에 대한 Lock을 잡고 있으므로 인해 내가 원하는 모드로 Lock을 할당 받을 수 없기 때문이다. 자신이 필요로 하는 Lock의 획득에 실패한 세션은 Owner가 작업을 완료하고 자신을 깨워줄 때까지(세마포어를 포스트해줄 때까지) Waiter 혹은 Converter Queue에서 대기하게 되며, 기다려도 소식이 없으면 3초 간격으로 timeout에 의해 일어나 혹시 Deadlock 상황이 아닌지 점검해 본 후 다시 Sleep에 빠져들기를 반복하게 된다. 튜닝관련 자료를 보다 보면 가끔 Enqueue에 대한 Wait이 많은 경우에 Enqueue_resource나 Enqueue_lock 파라미터를 증가시켜 주어야 한다는 가이드를 보게 되는 경우가 있는데 이 파라미터들은 Enqueue resource와 lock 배열의 크기를 늘려줄 뿐 특정 Enqueue 자원에 대한 동시 경합을 해소시키는 것과는 상관이 없다. Enqueue Wait를 해소하기 위한 구체적인 방법은 Enqueue type에 따라 달라지지만 결국은 Enqueue를 불필요하게 요청하는 경우가 없는지를 살펴 Enqueue에 대한 요청을 최소화하고 Enqueue를 점유하는 시간을 최대한 단축시키는 것이다. TX Enqueue에 대한 Wait은 대상 자원에 대한 Lock을 소유하고 있는 세션과 그 세션이 수행 중인 SQL을 찾아 트랜잭션이 장시간 지속되고 있는 이유가 무엇인지 애플리케이션 측면에서 조사해야 하며, SQ enqueue는 Sequence 값 할당 시 발생하는 경합이므로 cache값을 늘려줌으로써 완화시킨다거나 ST Enqueue의 경합이 존재할 경우에는 Locally managed tablespace를 사용하거나 Initial, Next 등의 extent 크기를 적당한 값으로 조정하여 실시간 공간할당을 감소시켜주는 등의 방법들이 Enqueue Wait에 대처하는 대표적인 사례이다. 지난 호에서 소개한 Session Waiter 스크립트는 Enqueue Wait 이벤트에 대해서 Enqueue type과 모드를 함께 표시하여 주도록 하고 있으며, 참고로 Enqueue type별 누적 Wait현황을 확인하고자 하면 아래 SQL을 수행하면 된다.


select q.ksqsttyp type,
           q.ksqstget gets,
           q.ksqstwat waits,
            round(q.ksqstwat/q.ksqstget,3) waitratio
       from sys.x$ksqst q
where q.inst_id = userenv('Instance')
      and q.ksqstget > 0
order by waits desc
/


■ Latch

오라클 운영 시에 하위레벨에서 내부적으로 처리되는 다양한 조작들이 latch의 관할 하에 수행되는데 V$LATCHNAME을 조회해보면 (9i 기준으로) 239 종류나 되는 Latch가 존재하는 것을 확인할 수 있다. 이 가운데 우리가 자주 접하게 되는 latch는 다음과 같은 정도이며 각 Latch의 기능은 관련 SGA별 Wait를 다룰 때 간단하게나마 소개하도록 하겠다.

Shared pool
library cache latch, shared pool latch, row cache objects
Buffer Cache
cache buffers chains latch, cache buffers lru latch, cache buffer handle
Redo log
redo allocation latch, redo copy latch, redo writing latch
OPS
dlm resource hash list


▷ Willing to wait 모드와 No-wait 모드

Latch 획득 방식은 No-wait과 Willing to wait 의 두 가지 모드로 구분할 수 있다. Willing to wait 모드는 Latch의 획득에 실패하면 좀더 시간을 끌면서 해당 Latch를 잡을 때까지 재시도를 해보는 방식을 말한다. 일차적으로는 CPU를 놓지 않고 정해진 횟수만큼 Spinning을 한 후 재시도를 해보다가 그래도 실패하면 CPU를 놓고 Sleep하다가 timeout되어 재시도하는 작업을 반복하면서 Latch의 획득을 노력하게 된다. Latch가 sleep에 들어가게 되면 'latch free' wait event 대기가 시작된다. sleep의 지속시간은 sleep 횟수가 늘어갈수록 점점 길어지게 되는데, 따라서 V$LATCH의 Gets와 Sleeps의 비율과 함께 Sleep1~sleep4 항목에서 몇차 Sleep까지 발생했는지 여부도 각 Latch Wait의 심각성을 판단하는 요소 가운데 하나가 된다.

No-wait 모드는 Willing to wait과는 달리 더 이상 미련을 두지 않고 해당 Latch에 대한 획득을 포기하는 것이다. No-wait 모드가 사용되는 경우는 두 가지가 있는데, 하나는 동일한 기능을 하는 Latch가 여러 개 존재하여 그 중에 하나만 획득하면 충분하여서 특정 Latch에 미련을 가질 필요가 없는 경우이다. 물론, 이 때에도 같은 기능의 모든 Latch에 대한 시도가 실패로 끝날 경우에는 Willing to wait 모드로 요청을 할 것이다. No-wait 모드가 사용되는 다른 한가지 경우는 dead lock을 피하기 위해서 이다. 오라클은 기본적으로 latch dead lock 상황을 피하기 위하여 모든 Latch에 level을 부여하여 정해진 순서를 따라서만 Latch를 획득하도록 하고 있는데, 필요에 의해 이 규칙을 어기고 Latch를 획득하고자 할 경우 일단 No-wait 모드로 시도를 해보는 것이다. 다행히 Latch를 잡으면 좋은 것이고 비록 latch를 잡을 수 없더라도 무한정 기다림으로써 dead lock 상태에 빠지는 일은 피할 수 있는 것이다. No-wait 모드의 Latch작업에서는 당연히 Latch 관련 wait이 발생하지 않으며, redo copy latch를 제외하고는 Willing to wait 모드로 Latch를 획득하는 경우가 훨씬 많다.

▷ Parent latch와 Child latch

Latch 가운데에는 동일 기능을 하는 Child latch들의 set으로 운영되는 Latch도 있으며 하나의 Latch로만 운영되는 Latch도 있다. 전자의 대표적인 예로는 cache buffers chains (버퍼캐쉬 블록 들을 같은 이름의 다수의 Latch가 나누어 담당)가 있으며, 후자의 예로는 shared pool latch (shared pool내에서 메모리 할당을 위해 획득해야 하는 Latch로 시스템에 하나만 존재)가 있다. 이와 같은 Latch 관련 통계 정보는 Parent latch와 Child latch의 개념으로 관리가 되는데 Latch set에서 개별 Child latch에 대한 통계정보는 V$LATCH_CHILDREN 뷰를 통해 조회할 수 있으며, 단일 Latch 혹은 Latch set의 마스터 Latch (parent)에 대한 통계정보는 V$LATCH_PARENT 뷰를 통해 조회할 수 있다.

지금까지 한 회 분량을 할애하여 Enqueue와 Latch에 대해 요약해본 이유는, 많은 Waiting이 SGA내의 공유자원 (Block, Cursor 등)에 대한 경합으로 인해 발생하며 이러한 경합은 다시 해당 자원에 대한 동시 액세스를 제어하는 Enqueue와 Latch에 대한 경합으로 흔히 드러나게 되므로 오라클의 Wait Event를 모니터링하기 위해서는 Enqueue와 Latch의 구조와 작동원리에 대해 이해하는 것이 필수적이기 때문이다.
 

출처: http://www.oracle.com/technology/global/kr/pub/columns/dbtuning04.html

'(DB) Oracle > 기타' 카테고리의 다른 글

Oracle - Top SQL 튜닝하기  (0) 2017.01.22
Oracle - Redo buffer 관련 Wait  (0) 2017.01.22
Oracle - Buffer Cache 관련 Wait  (0) 2017.01.22
Oracle - Shared Pool 관련 Wait  (0) 2017.01.22
Oracle - Wait Event 모니터링  (0) 2017.01.22
Posted by 농부지기
,

[ Oracle Wait Event 모니터링 ]

 

[1] Oracle Wait Event 모니터링

  흔히 DBA를 3D업종이라고 부르는 이유 가운데 하나는 몸은 고달픈데 반해 그 성과가 별로 티가 나지 않는다는 사실 때문일 것이다. 실제로, DBA가 수행해야 하는 일상적인 관리 업무들은 몸은 다소 피곤하게 만들지 몰라도 어느 정도 경험이 쌓이면 그리 부담을 주는 일은 아니다. 우리가 한단계 업그레이드된 전문가로서 인정 받는 DBA가 되기 위해서는 장애상황 혹은 유사 장애 상황에서 DB 모니터링 작업을 수행하고 분석할 수 있어야 한다. 시스템이 갑자기 느려지고 업무가 마비되는 상황에 맞닥뜨렸을 때 문제의 원인이 무엇인지를 집어낼 수 있는 능력이 있어야 하며 최소한 오라클의 문제인지 아닌지를 판단할 수는 있어야 몸으로 야간작업이나 때우는 DBA가 아니라 조직에 없어서는 안될 전문가로서의 나의 존재가치를 인정 받을 수 있을 것이다.

이 글에서는 오라클 Wait Event에 대하여 간단히 알아보고 일시적인 성능저하 상황에서 Wait Event를 모니터링하고 그 원인을 찾아가는 방법에 대하여 다루어 보고자 한다. 짧은 지면 위에 다룰 수 있는 내용도 제한되어 있고 글쓴이의 지식 또한 일천하지만 오라클 전문가가 되기 위해 같은 길을 가고 있는 동료로서 가진 지식 몇 가지 공유한다는 취지로 이 글을 쓴다.
오라클의 Wait Event 정보는 V$SYSTEM_EVENT, V$SESSION_EVENT, V$SESSION_WAIT 등이 있는데, 이 가운데 V$SESSION_WAIT는 각 세션이 현재 Waiting 하고 있는 Event나 마지막으로 Wait한 Event 정보를 보관하고 있으며, V$SYSTEM_EVENT와 V$SESSION_EVENT는 시스템이 Startup된 이후 각각 시스템 전체, 혹은 세션별로 발생한 Wait Event 정보를 누적하여 기록하고 있다.

오라클의 Wait Event는 성격에 따라 Network교신이나 IO를 위해 대기하는 일상적인 Wait와 특정 자원에 대해 여러 프로세스가 동시에 액세스하고자 할 때 발생하는 Wait, 별달리 할 일이 없어 대기하고 있는 Idle Wait 등 세가지 유형으로 구분할 수 있는데 그 유형에 따라 해석방법도 달라진다. 일단, Idle Wait는 일반적인 관심의 대상에서 제외되며 IO나 Network 관련 Wait는 작업량이 증가하면 같이 증가하는 Wait이므로 전체 서비스 시간(CPU time)과 비교하여 상대적으로 평가해야 하며 총 Wait time보다는 평균 Wait Time에 관심을 두고 분석을 해야 할 것이다. 시스템 자원에 대한 Wait는 데이터베이스 서버 튜닝시 가장 주된 관심 대상이 되며 이들 Wait에 대해서는 평균 Wait Time뿐만 아니라 총 Wait Time에도 관심을 가지고 분석해야 할 것이다. 유형별로 대표적인 Wait Event를 살펴본다면 아래와 같다.

[주요 Wait Event]

 
구분
이벤트명
설 명

일상적인
   Wait Event

db file scattered read Full Scan시 OS에 I/O를 요청해놓고 대기
db file sequential read Index Scan시 OS에 I/O를 요청해놓고 대기
(IO, Network) log file sync 변경 log buffer를 log file에 반영하는 동안 대기
DFS lock handle OPS 환경에서 노드간 분산 Lock 교환에 따른 대기
global cache cr request OPS 환경에서 노드간 Buffer Block 교환에 의한 대기
자원 경합에 따른
Wait Event 
enqueue Type에 따라 세분화 (24개의 enqueue type (9i))
latch free Name에 따라 세분화 (239개의 latch가 존재 (9i))
buffer busy waits 동일블록에 대한 동시 액세스에 따른 경합
free buffer waits free buffer를 할당위해 DBWR의 Write를 대기
Log buffer space Log buffer를 할당 받기 위해 LGWR의 write를 대기
library cache lock SGA내의 library cache를 참조하기 위한 대기(검색)
row cache lock SGA내의 dictionary cache를 참조하기 위한 대기
Idle Event  SQL*Net message from client Client로부터의 작업요청을 대기
Pmon timer PMON이 할일 없을 때 대기하는 Event

 

☞ 업무시간대에 시스템이 갑자기 느려졌다면서 오라클 서버에 문제가 없는지 문의가 들어오면 글쓴이는
   우선 아래의 SQL을 수행시켜본다.

 
select /*+ ordered / distinct /* 속도를 위해 v$sql을 조인할 경우 중복되는 레코드 제거 */
       s.sid SID, s.username, s.program, p.spid "OS-Pid",w.seconds_in_wait as "W_time(Sec)",
      decode(w.wait_time,0,'Wai-ting', 'Waited') Status, w.ename event,
--              p1text || ':' || decode(event,'latch free',p1raw, to_char(p1)) ||','||
--              p2text || ':' || to_char(p2) ||','|| p3text || ':' || to_char(p3) "Additional Info",
           q.sql_text
from ( select a.*, decode(a.event,'latch free', 'latch free (' ||b.name||')',
                           'row cache lock', 'row cache lock (' || c.parameter || ')',
                            'enqueue', 'enqueue ('||chr(bitand(p1, -16777216)/16777215)||
                                                    chr(bitand(p1,16711680)/65535)||':'||
                    decode(bitand(p1,65535), 1, 'N', 2, 'SS',3,'SX',4,'S',5,'SSX',6,'X') ||')',
                             a.event ) ename
       from  v$session_wait a, v$latchname b, v$rowcache c
       where a.p2 = b.latch#(+) and a.p1 = c.cache#(+) and c.type(+) = 'PARENT'
       and   a.event not in ('rdbms ipc message','smon timer','pmon timer','slave wait',
                              'pipe get','null event',
                     'SQL*Net message from client', 'SQL*Net message to client','PX Idle Wait',
                     'PX Deq: Execution Msg', 'KXFQ: kxfqdeq - normal deqeue',
                     'ges remote message', 'wakeup time manager', /* idle event 적절히 수정 */
                     'lock manager wait for remote message', 'single-task message')
        ) w, v$session s, v$process p, v$sql q
where w.sid = s.sid and s.paddr = p.addr
and s.sql_hash_value = q.hash_value(+) and s.sql_address = q.address(+)
order by w.ename;

SQL의 구체적인 내용이야 필요한 정보와 개인적 취향에 따라 달라지겠지만, 중요한 것은 일단 V$SESSION_WAIT 뷰로부터 실시간 Wait Event 정보를 얻어낸다는 것이다. 위 SQL을 수행했을 때 나타나는 결과가 없다면 일단 오라클 측면에서 업무성능을 심각하게 마비시키는 Waiting이 발생하고 있지 않다고 봐도 큰 무리가 없을 것이다.

일반적인 상태에서는 주로 'db file sequential read'나 'db file scattered read' 가 나타날 텐데, 이러한 Wait Event는 보통 짧은 시간 동안 지속되며 대상 자원(블록)을 바꿔가며 Wait가 반복되는 형태로 나타날 것이다. 이는 작업 처리량이 많을 때 일상적으로 발생하는 IO관련 Wait Event이므로 해당 세션에서 IO를 제법 많이 유발하고 있다는 정도로 이해하고 넘어가면 될 것이다. 물론, Wait의 지속시간이 길거나 지나치게 빈번히 나타나는 SQL에 대해서는 비효율적인 실행계획을 수립하고 있지 않은지 검토해서 튜닝해 주어야 한다.

성능저하의 원인이 오라클 쪽에 있는 경우에는 특정 자원에 대한 Waiting이 상당히 오랫동안 지속되어 현재까지 Waiting이 진행 중인 세션들(STATUS가 'Wai-ting' (wait_time=0)이며 'W_time(sec)' (seconds_in_wait) 값이 상당히 큰 세션)이 존재할 가능성이 높다. 오라클의 내부적인 작업들은 매우 짧은 기간에 처리되어야 하므로, Idle event(where절에서 not in으로 처리한 부분, 버전에 따라 달라질 수 있다.) 이외의 특정 Wait Event가 눈에 띌 정도로 검출된다는 것은 오라클 내부적으로는 훨씬 더 많은 Waiting이 발생하고 있다고 생각해야 한다. 바로 이런 세션들이 문제의 범인들이며 이제부터 DBA는 이들 Wait Event에 대한 원인을 파악하여 조치하는 작업을 해주어야 한다. 각각의 Wait Event에 따라 원인을 추적하고 조치하는 방법은 달라질 것이다.

다음 호에서는, 자주 경험하는 몇가지 대표적인 Wait Event들에 대하여 SGA 영역별로 구분하여 좀 더 자세히 살펴보고, 그에 앞서 Lock 또는 Latch Event의 이해를 위해 필요한 Enqueue와 Latch의 개념을 간단히 알아보도록 하겠다.
 

 

'(DB) Oracle > 기타' 카테고리의 다른 글

Oracle - Top SQL 튜닝하기  (0) 2017.01.22
Oracle - Redo buffer 관련 Wait  (0) 2017.01.22
Oracle - Buffer Cache 관련 Wait  (0) 2017.01.22
Oracle - Shared Pool 관련 Wait  (0) 2017.01.22
Oracle - Enqueue와 Latch 개념 이해하기  (0) 2017.01.22
Posted by 농부지기
,