ORACLE/TroubleShooting2014. 3. 23. 22:46
반응형

WORKSHOP : SHARED POOL

CONCEPT
 SGA를 관리하는 매커니즘, 파라메터 정보, 실행된 SQL, SQL 분석/ 실행 정보 및 오라클 오브젝트 정보를 저장하는 메모리 공간.동적 영역과 고정 영역으로 분리됨.

 동적영역 - SHARED_POOL_SIZE 파라메토를 사용하여 설정 가능
  LIBRARY CACHE
   - 사용자가 수행한 SQL
   - Recursive SQL
   - 분석정보
   - 실행계획

  DICTIONARY CACHE
   - Table, Index, Function, Trigger 등 오브젝트 정보 및 권한등의 정보

 고정영역
  SGA를 관리하는 메커니즘 및 오라클 파라메터 정보 저장.
  SHOW SGA 명령으로 나오는 Fixed Size 의 값이 고정 영역의 크기.


PARAMETERS
 SHARED_POOL_SIZE
  Shared pool 의 크기를 결정한다.

 SHARED_POOL_RESERVED_SIZE
  4400 Bytes 이상의 SQL 이 수행될 경우 이 공간이 충분하지 않다면,  ORA-4031 발생한다. 해당 예약 공간을 설정하지 않으면 기본적으로 Shared pool 의 5%가 할당되고 최대 Shared pool 의 50% 이상 설정할 수 없다.


ORA-4031. Unable to Allocate %s Bytes of shared memory
 SQL 정보를 저장할 수 있는 충분한 크기의 사용 가능 메모리 조각이 부작할 시 발생한다. 이때 다음의 방법을 통해 이 문제를 해결할 수 있다.

 ALTER SYSTEM FLUSH SHARED_POOL;
  Shared Pool 의 모든 내용을 초기화 한다. 하지만 다시 들어오는 SQL문은 다시 새로이 Hard Parsing 이 수행되므로 부하가 순간 발생할 수 있다.

 SHARED_POOL_RESERVED_SIZE 파라메터 값 증가.

 LARGE POOL 설정.



PARSE
 오라클은 사용자가 SQL 구문을 수행하면 그 SQL을 분서갛여 실행할 수 있는 단계를 만든다. SOFT PARSING 과 HARD PARSING 이 존재하며 SOFT PARSING 은 이미 SHARED POOL에 저장되어 있는 정보를 재사용하는 것이며, HARD PARSING 은 재사용하지 못하고 다시 구문 분석을 수행하게 된다(부하 높음).

 하드 파싱을 피하기위해서는 다음 사항을 준수한다.
  - 대소문자 일치
  - 띄어쓰기 일치
  - 오브젝트 소유자 일치





SHARED POOL 의 메모리 관리
 SHARED POOL 은 HEAP 이라는 메모리 관리 기법으로 관리한다. HEAP 은 Top-Level Heap 과 그 하위에 여러개의 Sub-Heap 으로 구분하고 또 Heap은 Linked List 구조의 EXTENT 들로 구성되어져 있으며 Extent는 여러개의 chunk 로 구성되어 있다.





SHARED POOL HEAP 구조도

 Bucket
  각각의 정해진 기준의 크기 이하의 chunk 들로만 구성. Bucket 이 아래로 갈수록 chunk들의 크기가 크다.

 Recreatable
  재생성 가능한 상태.  Unpinned (사용되지 않는 상태) 일 때 재사용 가능. 즉, 이미 한번 사용되었지만, 다시 사용될 확율이 낮아져서 재사용이 가능한 상태가 된 것. 이러한 상태의 Chunk를 묶어 LRU List로 관리한다.  ( X$KGHLU )

 Freeable
  Session 이나 Call 동안에만 필요한 객체를 저장하고 있는 상태. Session 의 유지 시간은 알 수 없으므로, Chunk 가 필요할때 할당의 대상이 되지는 않는다.

 Permanent
  영구적인 객체를 저장하고 있으며 사용할 수 없는 Chunk 이다.



SHARED POOL 의 메모리 관리
 Free List 검색후 Free List에 사용할 공간이 부족하면 LRU List 를 탐색한다. 그래도 공간이 없으면 Reserved Free List 를 탐색하고 없으면 Space Free Memory탐색. 없으면 ORA - 4031.

 Oracle 9i 부터는 하나의 Shared pool 을 최대 7개까지의 Sub pool 로 나누어서 관리를 수행한다.  Hidden Parameter 인 "_KGHDSIDX_COUNT" 를 이용하여 하나의 SHARED POOL 을 나누어 관리한다.  CPU 4개에 SHARED_POOL_SIZE 가 250메가 이상일 시 Sub Pool 사용을 권고한다.  각각의 Sub pool 당 독다적인 Free List, LRU List, Shared pool latch를 가지기 때문에 부족한 자원에 대한 경합을 감소시킬 수 있으나 CPU 개수나 SHARED_POOL_SIZE 의 크기가 충분하지 않으면 ORA-4031을 발생할 수 있다.



LIBRARY CACHE
 라이브러리 캐시는 Hash function, Bucket, Handle list, LCO 로 구성되어 있다. Library Cache Manager (KGL) 에 의해 관리되고 내부적으로 Heap Manager (KGH) 를 이용한다.  할당된 Free Chunk 는 LCO(Library Cache Object) 와 handle 을 저장하는데 사용된다.


 동일 Hash 값으로 이루어진 Handle 들은 linked list 로 Hash Bucket 에 담긴다. 추후 SQL문이 들어오면 Hash function 을 이용해 나온 값이 동일한 값을 가진 Handle  이 있는지를 찾게 된다.  Handle 은 크게 Name (SQL Text) 와 Meta 정보로 이루어져 있다. 이를 LCO (Library Cache Object) 라고 부른다.

  DEPENDENCY TABLE
 해당 LCO가 의존하는 LCO들의 Handle 포인트와 해당 LCO 가 뷰를 포함하고 있다면, 뷰에서 참조하는 Source Table 에 대한 Library Cache Handle 주소를 나타내며 해당 LCO가 패키지일 경우 패키지에서 사용하고 있는 펑션이나 프로시져에 대한 Library Cache Handle 주소를 가진다.  해당 LCO 가 SQL 문장일 경우 SQL 문에서 참조하는 테이블에 대한 Library Cache Handle 주소를 가지게 된다.  (V$DB_OBJECT_DEPENDENCY  :  Shared Pool의 Dependency 정보 확인)

 CHILD TABLE
 동일 SQL문장에 대하여 VERSION COUNT 가 증가 한 경우 각각의 LCO에 대한 주소 값을 나타낸다. VERSION COUNT 가 증가하는 경우는 동일 쿼리지만 SCHEMA 가 다르거나,  SQL  수행시의 파라메터가 다르거나, NLS 값이 틀리거나 하는 등의 이유가 있을 수 있다. 정확히 알기 위해서는 V$SQL_SHARED_CURSOR 뷰를 참조.

 SQL TEXT 등을 해시 함수를 적용해 생성된 해시값을 이용해 적절한 해시 버킷을 할당하며, 같은 해시 값을 지니는 객체들은 체인으로 관리된다. 하나의 라이브러리 캐시 핸들은 하나의 라이브러리 캐시 오브젝트 ( LCO)를 관리한다. 핸들은 실제 LCO 에 대한 메타정보 및 포인터 역할을 하며 LCO가 실제 정보를 담고 있다.



LIBRARY CACHE CONTENTION
 Hard Parsing 이 자주 발생하게 되면 그만큼 Library Cache 를 탐색하는 횟수가 늘어나 Library Cahce Latch 를 보유하는 시간과 횟수가 늘어나게 된다.
 (Library Cache Latch - 간단히 Library Cache 를 사용할 수 있는 권한 증명서)
 Hard Parsing 은 Library Cache 영역에 대한 탐색 뿐만 아니라 추가적인 Chunk 할당이 필요하기에 그만큼 Library Cache Latch를 보유하는 시간이 늘어나게 된다.



DICTIONARY CACHE
 SEVER PROCESS 가 쿼리를 수행하기 위해 해당 쿼리의 문법검사, 권등을 체크하기 위해 참조하는 캐시이다.  일반적인 데이터베이스 정보를 저장하고 있는 캐시.
 DICTIONARY VIEW 는 4가지 형태로 나뉘어져 있다.

  USER_
   해당 스키마가 소유한 객체들
  ALL_
   해당 스키마가 접근 가능한 모든 객체
  DBA_
   DBA만이 접근 가능한 정보로써, DB의 정보를 포함
  V$_
    DB의 성능정보를 보는 동적 성능뷰 (Performance View)


반응형
Posted by [PineTree]
ORACLE/OWI2013. 6. 23. 21:42
반응형

출처 :  http://blog.naver.com/bj2118/80069059099

shared pool 의 dump한결과

-Memory :공간 요청시 chunk 단위로 할당

-Freelist : Free chunk의 목록들

-LRU list : 현재 사용중이지 않는 재생성 가능한 chunk목록들

-Reserved Freelist : 최상위 Heap에만 존재, shared pool의 예약 영역에 대한 Freelist

-Freelist에서 원하는 크기의 chunk검색 -> LRU list 검색 -> 특정 크기 이상이면 Reserved list 검색

 ->모두 실패하면 ora-4031에러 발생

 

 

아래와같이 dump파일을 텍스트 문서로 하면 처음볼수있는건 시스템에 기본정보들을 볼수 있다.

 

/u01/app/oracle/admin/orcl/udump/orcl_ora_5836.trc                                                 
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production                             
With the Partitioning                                                                              
ORACLE_HOME = /u01/app/oracle/product/10.2.0/db_1                                                  
System name: Linux                                                                                 
Node name: localhost.localdomain                                                                   
Release: 2.6.9-42.0.0.0.1.EL                                                                       
Version: #1 Sun Oct 15 13:58:55 PDT 2006                                                           
Machine: i686                                                                                      
Instance name: orcl                                                                                
Redo thread mounted by this instance: 1                                                            
Oracle process number: 22                                                                          
Unix process pid: 5836

 

shared pool의 heap구조의 Top heap에 해당하는부분에 정보이다.

 

******************************************************                                             
HEAP DUMP heap name="sga heap"  desc=0x2000002c          <-----------  Top heap            

extent sz=0x32c8 alt=108 het=32767 rec=9 flg=-126 opc=0                                           
 parent=(nil) owner=(nil) nex=(nil) xsz=0xfd0                                                      
*****************************************************

HEAP DUMP heap name="sga heap(1                                                                    
 extent sz=0xfc4 alt=108 het=32767 rec=9 flg=-125 opc=0                                            
 parent=(nil) owner=(nil) nex=(nil) xsz=0x400000

 

EXTENT 상태를 확인할수 있는 자료

 

EXTENT 0 addr=0x26c00000         <------익스텐드                                                            
  Chunk 26c00038 sz=  4194248    perm      "perm           "  alo=134768   <---청크                        
EXTENT 1 addr=0x29000000                                                                           
  Chunk 29000038 sz=       24  R-freeable  "reserved stoppe"                                       
  Chunk 29000050 sz=   212888  R-free      "               "                                       
  Chunk 29033fe8 sz=       24  R-freeable  "reserved stoppe"                                       
  Chunk 29034000 sz=  3979072    perm      "perm           "  alo=3979072                          
  Chunk 293ff740 sz=     2240    free      "               "                                       
EXTENT 2 addr=0x29400000                                                                           
  Chunk 29400038 sz=       24  R-freeable  "reserved stoppe"                                        
  Chunk 29400050 sz=   212888  R-free      "               "                                       
  Chunk 29433fe8 sz=       24  R-freeable  "reserved stoppe"                                       
  Chunk 29434000 sz=  3214744    perm      "perm           "  alo=3214744                          
  Chunk 29744d98 sz=   765044    perm      "perm           "  alo=765044                           
  Chunk 297ffa0c sz=     1524    free      "               "                                       
EXTENT 3 addr=0x29800000                                                                           
  Chunk 29800038 sz=       24  R-freeable  "reserved stoppe"                                       
  Chunk 29800050 sz=   212888  R-free      "               "                                       
  Chunk 29833fe8 sz=       24  R-freeable  "reserved stoppe"                                       
  Chunk 29834000 sz=  3645256    perm      "perm           "  alo=3645256                          
  Chunk 29badf48 sz=   333196    perm      "perm           "  alo=333196                           
  Chunk 29bff4d4 sz=     2860    free      "               "              

 

freelist에 목록이 주소값으로 나와있으면 29bff4d4 이주소로 검색하면

FREE LISTS:Chunk 293ff740 sz=     2240    free 목록을 확인할수 있다.

 

FREE LISTS:                                                                                        
 Bucket 0 size=16           <----  버킷                                                                        
 Bucket 1 size=20                                                                                  
 Bucket 2 size=24                                                                                  
 Bucket 3 size=28                                                                                  
 Bucket 4 size=32                                                                                  
 Bucket 5 size=36                                                                                  
 Bucket 6 size=40                                                                                  
 Bucket 7 size=44                                                                                  
 Bucket 8 size=48                                                                                  
 Bucket 9 size=52                                                                                  
 Bucket 10 size=56                                                                                 
 Bucket 11 size=60                                                                                 
 Bucket 12 size=64                                                                                 
 Bucket 13 size=68                                                                                 
  Chunk 2a7fffbc sz=       68    free      "     <---- 프리 청크                        

..... 생략

Free lists는 프리chunk의 목록들이면 여기에 나오는 chunk 주소값은 heap구조상으로 익스텐드에

위치를 나타내준다.

 

UNPINNED RECREATABLE CHUNKS (lru first):                                                      
SEPARATOR                                                                                          
Unpinned space     =        0  rcr=0 trn=0                                                         
PERMANENT CHUNKS:                                                                                  
  Chunk 26c00038 sz=  4194248    perm      "perm           "  alo=134768                           
  Chunk 29badf48 sz=   333196    perm      "perm           "  alo=333196                           
  Chunk 29744d98 sz=   765044    perm      "perm           "  alo=765044                           
  Chunk 29034000 sz=  3979072    perm      "perm           "  alo=3979072                          
  Chunk 29434000 sz=  3214744    perm      "perm           "  alo=3214744                          
  Chunk 29834000 sz=  3645256    perm      "perm           "  alo=3645256                          
  Chunk 2b7ece44 sz=    76816    perm      "perm           "  alo=76816                            
  Chunk 2abff884 sz=     1040    perm      "perm           "  alo=1040                             
  Chunk 2afe0a1c sz=   128016    perm      "perm           "  alo=128016                           
  Chunk 2abe3c74 sz=   113680    perm      "perm           "  alo=113680                           
  Chunk 29fffa7c sz=     1040    perm      "perm           "  alo=1040                             
  Chunk 2a3fd14c sz=    11280    perm      "perm           "  alo=11280                            
  Chunk 29c34000 sz=  3979900    perm      "perm           "  alo=3979900                           
Permanent space    = 40015520 

 

lru list 정보를 확인할수 있으며 여기에 있는 목록들은 현재사용하지않은 재생성 가능한 chunk의 목록들이다.

 

RESERVED FREE LISTS:   <-----  예약 프리리스트                                     
 Reserved bucket 0 size=16                                                                         
 Reserved bucket 1 size=4400                                                                       
 Reserved bucket 2 size=8204                                                                       
 Reserved bucket 3 size=8460                                                                       
 Reserved bucket 4 size=8464                                                                       
 Reserved bucket 5 size=8468                                                                       
 Reserved bucket 6 size=8472                                                                       
 Reserved bucket 7 size=9296                                                                       
 Reserved bucket 8 size=9300                                                                       
 Reserved bucket 9 size=12320                                                                      
 Reserved bucket 10 size=12324                                                                     
 Reserved bucket 11 size=16396                                                                     
 Reserved bucket 12 size=32780                                                                     
 Reserved bucket 13 size=65548 

 

이상 대략적으로 재가 직접 Dump를 떠서 나름 공부해보면서 정리해본 자료입니다.

어차피 owi에 나와있는내용 한번 정리한 샘이라 책읽어 보시면 좀더 자세히 아실듯해요 ^_^

 

 

반응형
Posted by [PineTree]
ORACLE/TroubleShooting2011. 12. 6. 10:39
반응형

Share pool과 성능문제

 


  xx지원 오라클 장애처리
  ========================
  작성자 :

   1. 장애처리
      장애 시간 : 2006-07-21 11:34
      장애 서버 : xx지원 서버2의 오라클 데이터베이스
      장애 유형 : 오라클 데이터베이스 인스턴스 다운
      장애 원인 : 오라클의 LMD(LOCK MONITOR DEADON) 다운으로 오라클 인스턴스 다운이 발생함
                  (장애분석 참조)
      장애 조치 : 오라클 인스턴스 재시작함
      복구 시간 : 2006-07-21 11:53
      장애 예방방안 : 장애대처 예방 참조


   2. 장애분석
     [ alert! 로그 파일]
       Fri Jul 21 11:34:26 2006                      ==> 장애 시간
       LMD0: terminating instance due to error 4031  ==> 장애 메시지
       Instance terminated by LMD0, pid = 19848      ==> 데이터베이스 다운

     [ trace 파일 분석 ]
      파일명 : llmd0_19848_hiraops2.trc
       *** 2006-07-21 11:34:26.346
       *** SESSION ID:(3.1) 2006-07-21 11:34:26.306
       error 4031 detected in background process
    
     [ 장애원인 ]
       ORA-4031 : shared pool memory 분석으로 LMD 프로세스 다운으로 발생함
       Shared Pool의 정확인 영역은 나타나지 않음

       <참조 : 메시지 >
       04031, 00000, "unable to allocate %s bytes of shared memory (\"%s\",\"%s\",\"%s\",\"%s\")"
       *Cause:  More shared memory is needed than was allocated in the shared pool.
       *Action: If the shared pool is out of memory, either use the dbms_shared_pool package to pin
                large packages,reduce your use of shared memory, or increase the amount of available shared
                memory by increasing the value of the INIT.ORA parameters "shared_pool_reserved_size" and
                "shared_pool_size".
                If the large pool is out of memory, increase the INIT.ORA parameter "large_pool_size".


       < Ora-4031 란 ? >
        이 에러는 사용자가 특정 Object를 사용하고자 할 때 해당 Object를 위해 Shared_Pool에 공간을 할당하려 할 때 충분한
        공간을 얻지 못하는 경우이다
        Shared_Pool 영역에 차지하는 크기가 큰 PL/SQL 사용시 오라클은 공간 확보를 위해 현재 사용되지 않는 Object를 Flush시킨다.
        기존 V7.2. 이하에서는 특정 프로시저를 Shared_Pool에 올리기 위해 연속된 공간을 필요로 하였으나, 이후 버전에
       서는 꼭 연속되지 않아도 사용이 가능하여 ORA-4031 에러가 발생하는 경우가 많이줄어들었다.
        이의 해결을 위해서는 Shared_Pool을 늘려주도록 한다 .
        이 에러를 유발시키는 문제인 메모리의 단편화 (fragmentation)를 줄이기 위해서, 또는 일반적인 경우 자주 사용하는 Object가
        메모리에서 밀려 내려가는 경우를 없애기 위해서 Object를 미리 Shared_Pool에  Keep 한다.


   3.장애 예방 방안
    [ 목적 ]
     - Shared Pool Memory 부족(ORA-4031) 장애발생 예방

    [ 예방 방법 ]
     - shared pool size , shared pool reserved size , large pool size를 증가 한다.
    
    [ Shared Pool Memory 할당 값]
      #shared_pool_size              = 471859200             # 450MB
      #shared_pool_reserved_size     = 47185920              # shared pool * 10%
      #shared_pool_size              = 512000000             # 500MB             2005.07.21
      #shared_pool_reserved_size     = 51200000              # shared pool * 10% 2005.07.21
 
       shared_pool_size               = 629145600              # 600MB             2005.08.08
       shared_pool_reserved_size      = 62914560               # shared pool * 10% 2005.08.08
       java_pool_size                = 2097152
       large_pool_size               = 10M                   # 2004/10/30

    [ 메모리 사용률 ]
      전체 메모리 : 19.9G  
      사용률 : Sys Mem  : 4.68GB   User Mem:  2.71GB   Buf Cache: 1.99GB   Free Mem: 10.5GB


    [ shared pool free memory 확인 QUERY 및 flush 명령어]
  
    SQL> select v$sgastat.pool, to_number(v$parameter.value) value, v$sgastat.bytes,
          (v$sgastat.bytes/v$parameter.value)*100 "Percent Free"
          from v$sgastat , v$parameter
          where v$sgastat.name = 'free memory'
          and v$parameter.name = 'shared_pool_size';

          POOL          VALUE          BYTES   Percent Free
         ---------------------------------------------------------------
         shared pool 629145600 140415416 22.3184293111165   <-- free space 확인
         large pool 629145600 299984         0.0476811726888021
         java pool 629145600 2097152         0.333333333333333

    SQL> alter system flush shared_pool;   <-- 단편화된 조각화를 flush 해주는 방법(메모리 조각모음) (업무외시간에 수행)

 

    [ Library Cache Fragmentation 확인 Query]

         select
             decode(sign(ksmchsiz - 812), -1, (ksmchsiz - 16) / 4,
               decode(sign(ksmchsiz - 4012), -1, trunc((ksmchsiz + 11924) / 64),
                 decode(sign(ksmchsiz - 65548), -1, trunc(1/log(ksmchsiz - 11, 2)) + 238, 254 )))  bucket,
             sum(ksmchsiz)  free_space,  count(*)  free_chunks,  trunc(avg(ksmchsiz))  average_size,
             max(ksmchsiz)  biggest
           from
             sys.xm$ksmsp
           where
             inst_id = userenv('Instance') and  ksmchcls = 'free'
           group by
             decode(sign(ksmchsiz - 812), -1, (ksmchsiz - 16) / 4,
               decode(sign(ksmchsiz - 4012),-1, trunc((ksmchsiz + 11924) / 64),
                 decode(sign(ksmchsiz - 65548),-1, trunc(1/log(ksmchsiz - 11, 2)) + 238, 254)))

           BUCKET FREE_SPACE FREE_CHUNKS AVERAGE_SIZE    BIGGEST
           ---------- ---------- ----------- ------------ -------------------------------------------------------
                    6       92000         2300         40         40
                    8       1392          29           48         48
                   10       1456          26           56         56
           ……
           위의 결과처럼 shared pool 영역에 작은 chunk 들의 다수 존재하는 경우에는 free list   검색시 shared pool latch를 장시간 holding하게 되며,
           이는 shared pool latch free 대기 현상이 발생할 가능성을 높여주게 된다. 일반적으로 hard parsing에 의해 이러한 현상들이 발생하게 됨.
          
          
           
          
     [ Shared Pool size 적절성 확인 Query ]
         
                                                     
           column kghlurcr heading "RECURRENT|CHUNKS"
           column kghlutrn heading "TRANSIENT|CHUNKS"
           column kghlufsh heading "FLUSHED|CHUNKS"  
           column kghluops heading "PINS AND|RELEASES"
           column kghlunfu heading "ORA-4031|ERRORS" 
           column kghlunfs heading "LAST ERROR|SIZE" 
          
           select
             kghlurcr "RECURRENT|CHUNKS" ,
              kghlurcr *3,
             kghlutrn "TRANSIENT|CHUNKS" ,
             kghlufsh "FLUSHED|CHUNKS"  ,
             kghluops "PINS AND|RELEASES" ,
             (kghlufsh/ kghluops) *100,
             kghlunfu "ORA-4031|ERRORS" ,
             kghlunfs "LAST ERROR|SIZE"
           from
             sys.x_$kghlu
           where
           inst_id = userenv('Instance');


          
           RECURRENT  TRANSIENT    FLUSHED        PINS AND    ORA-4031 LAST ERROR
               CHUNKS     CHUNKS     CHUNKS        RELEASES     ERRORS       SIZE
           ---------- ---------- ---------------  ---------- -----------------------------------------------------------------
                  587       1687          8946       28416904          0          0
                 


--  일반적으로 Transient list가 Recurrent List 의 3배 이상이면 shared pool 이 oversize  된 것이며, chunk flush 수치가
  --         pins and released 수치의 5% 이상이면 shared pool 이 작게 설정된 것이라고 볼 수 있다.
          

 

 

shared pool 의 free 공간 확인

 

 

select to_number(v$parameter.value) value, v$sgastat.bytes,
(v$sgastat.bytes/v$parameter.value)*100 "Percent Free"
from v$sgastat, v$parameter
where v$sgastat.name = 'free memory'
and v$parameter.name = 'shared_pool_size';

 

 

Shared Pool 관련 wait

 


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 )

 

 

☞   4-6 library cache 알고리즘

 

라이브러리 캐쉬는 lru 알고리즘에의해 관리가 되며

문장이 이미 캐쉬에 저장되어 있는가를 찾기 위하여, 오라클 서버는 다음을 수행합니다:

 

1. ASCII 텍스트의 수치로 문장을 줄임
2. 이 수치에 해시 함수 사용

 

 


☞   4-7  shared pool latch 

 

SQL 이 공유되지 못하고 파싱해달라고 하는 SQL 이 많아지면 공간을 할당 받아야하는데 이때
공간을 할당 받을때 메모리에 락(latch) 를 건다. latch 를 사용하는 이유는 파싱해달라고 요청하는
sql 에 대하여 순서를 정하는 것인데 먼저 요청한 sql 에 대하여 작업을 원할히 수행하기 위해 메모리에 락을 거는것이다.즉 동시 엑세스를 제어하기 위해 latch 를 사용한다.

그런데 조각화(단편화) 가 심해지면 free list 가 그만큼 길어지므로 공간 할당받을때 시간이 많이 소유될것이고 이로 인해 발생하는 wait event ( latch free(library cache) ) 가 다량으로 발생할것이다.

이를 해결하기 위해서는

 

1. 바인드변수 사용
2. cursor_sharing 사용
3.  shared pool size 늘린다.
4. large pool 을 구성한다.

 

☞   4-8  shared pool 에 공유되지 않은 SQL 에 대한 정보 보기


select  *
 from v$sqlarea
 where executions < 5
  order by upper(sql_Text)
 
 
select sql_Text, parse_calls, executions
   from v$sqlarea
     order by parse_calls; 

 


☞   4-12 ~            실습


v$sqlarea


(라이브러리 캐쉬: 문장저장)


동일한 문장


1. 대소문자
2. 스키마(schema)
3. 공백
4. 주석
5. bind 변수의 type(아래설명)


*****************************************
scott1
실행
 SQL> select empno,ename from emp where deptno=10;

      EMPNO ENAME
 ---------- ----------
       7782 CLARK
       7839 KING
       7934 MILLER


internal에서 실행
 SQL> ed
 Wrote file afiedt.buf

      select sql_text,SHARABLE_MEM,EXECUTIONS
      from v$sqlarea
     where sql_text like 'select empno,ename from emp where%';
  

 SQL_TEXT     SHARABLE_MEM  EXECUTIONS
 -------------------------------------------------------------- ----------
 select empno,ename from emp where deptno=10             5234   1
 
 사용했던 문장이 나옴


scott1
변수 선언
 SQL> variable v1 varchar2(10)
 SQL> declare
   2  begin
   3     :v1 := '10';
   4  end;
   5  /

 PL/SQL procedure successfully completed.

 SQL> select empno, ename from emp where deptno=:v1;

      EMPNO ENAME
 ---------- ----------
       7782 CLARK
       7839 KING
       7934 MILLER

internal
 SQL> /

 SQL_TEXT                                           SHARABLE_MEM EXECUTIONS
 -------------------------------------------------- ------------ ----------
 select empno,ename from emp where deptno=10                5234          1
 select empno,ename from emp where deptno=:v1               5067          1


scott1
변수값을 바꾸어줌
 SQL> declare
   2  begin
   3     :v1 := '20';
   4  end;
   5  /

 PL/SQL procedure successfully completed.

 SQL> select empno,ename from emp where deptno=:v1;

      EMPNO ENAME
 ---------- ----------
       7369 SMITH
       7566 JONES
       7788 SCOTT
       7876 ADAMS
       7902 FORD

internal
scott의 결과는 달라도 새로 파싱을 안함
 SQL> /

 SQL_TEXT                                           SHARABLE_MEM EXECUTIONS
 -------------------------------------------------- ------------ ----------
 select empno,ename from emp where deptno=10                5234          1
 select empno,ename from emp where deptno=:v1               5067          2

 

문제) select empno,ename from emp where deptno=30 을 하고 출력해보아라 !!!  


   
scott2


변수형을 넘버로 선언
 SQL> variable v1 number
 SQL>  declare
    2  begin
    3  :v1 :=20;
    4  end;
 PL/SQL procedure successfully completed.

 SQL> select empno,ename from emp where deptno=:v1;

      EMPNO ENAME
 ---------- ----------
       7369 SMITH
       7566 JONES
       7788 SCOTT
       7876 ADAMS
       7902 FORD

internal

scott2에 실행한 문장후 크기가 늘어남 (파싱계획변경)
 SQL> /

 SQL_TEXT                                           SHARABLE_MEM EXECUTIONS
 -------------------------------------------------- ------------ ----------
 select empno,ename from emp where deptno=10                5234          1
 select empno,ename from emp where deptno=:v1               8939          3

 

********** bind type에 따라 파싱이 다르다 ****************

 

 

☞   4-13           실습

1) v$librarycache 를 통해 hit율(gethitratio)를 분석

   - gets    : 사용자가 실행한 SQL문이 구문 분석되어 라이브러리 캐시 영역에 로드되려 했던 수.
   - gethits : 그 중 로드되었던 수
   - hit율(gethitratio)이 90% 이상일때 좋은 성능 기대

select namespace , gets , gethits,gethitratio
from v$librarycache
where namespace = 'SQL AREA' ;

NAMESPACE         GETS    GETHITS GETHITRATIO
--------------- ---------- ---------- -----------
SQL AREA            141767     141498     .99810252

  <= GETHITRATIO 컬럼 값이 90%이상이면 라이브러리 캐시 영역이 개발자들의 SQL 파싱정보를
      저장하기에 충분한 메모리 공간을 확보하고 있슴을 의미하며, 만약 90% 이하라면 성능이 저하
      될 수 있다는 것을 의미.
      물론 90% 이하라도 사용자들이 성능에 만족한다면 튜닝 대상이 안될 수도 있으며 반드시 튜닝
      을 해야 할 필요는 없다.

  ▷ 유의사항
     - 히트율 분석은 기업에서 가장 일을 바쁘게 진행하고 있는 시간대의 분석 결과를 기준으로
        하여야 한다.

  ▷ 초치사항
     - HIT율이 90% 이하일 경우 SHARED_POOL_SIZE 파라메터 값을 높게 설정.
    ex) initSID.ora
               ......
          SHARED_POOL_SIZE = 32000000  <= 이전 보다 큰 값으로 변경
              .....
    
2) v$library 자료사전을 통해 RELOAD 비율 분석.

   - RELOADS 비율  =  ( Reloads / Pins ) * 100
   - Library Cache Area 의 크기가 너무 작아서 사용자의 SQL 구문분석 정보가 로드되지 못하고
     가장 오래된 SQL문 정보를 삭제 후 사용자의 SQL 문장이 다시 실행될 때 Reloads 증가.
  - 구분분석된 SQL문에서 사용된 객체가 다른 사용자에 의해 삭제된 상태에서 다시 SQL문이
     재실행될 때에는 RELOADS 컬럼값이 증가.
  - PINS : 구문분석되어 Library Cache Area 에 저장될 수 있었던 SQL 정보.
  - PINS 컬럼에 대한 Realods 컬럼의 백분율이 1% 미만일 때 좋은 성능 기대.

select sum(pins),sum(reloads),sum(reloads)/sum(pins)
from v$librarycache
where namespace = 'SQL AREA' ;

SUM(PINS) SUM(RELOADS) SUM(RELOADS)/SUM(PINS)
----------      ------------     ----------------------
    320823            10                   .00003117
  
<= PINS에 대한 RELOADS의 비율이 1% 미만일 때 라이브러리 캐시 영역의 크기가 AQL 파싱정보
     를 저장하기에 충분하다는 것을 의미. 1% 이상이라면 성능이 저하될 수도 있다는 것을 의미.

3) v$librarycache 를 통해 SQL문에서 사용된 객체가 다른 사용자들에 의해 얼마나 자주
     삭제,변경되었는 지를 분석하는 방법.
    주로 ANALYZE ,ALTER , DROP명령어에 의해 테이블 구조가 변경되는 경우에 발생.


select namespace, invalidations
from v$librarycache
where namespace = 'SQL AREA' ;

NAMESPACE       INVALIDATIONS
--------------- -------------
SQL AREA                    0

  <= INVALIDATIONS 컬럼의 값이 높게 출력 되거나 계속적으로 증가 값을 보인다면 공유 풀 영역
     에 작아서 성능이 저하되도 있음을 의미. 즉, 불필요한 재파싱. 재로딩 작업이 발생할 가능성이 높
     아지는 것이다.

 

 

 


☞   4-14 ~            실습


SQL> alter system set cursor_sharing=force scope=both;

시스템이 변경되었습니다.

SQL>
SQL>
SQL> select sql_text,SHARABLE_MEM,EXECUTIONS
           from v$sqlarea
          where sql_text like 'select empno,ename from emp where%';

SQL_TEXT
--------------------------------------------------------------------------------
SHARABLE_MEM EXECUTIONS
------------ ----------
select empno,ename from emp where deptno=10
        6693          1

select empno,ename from emp where deptno=30
        6725          1

select empno,ename from emp where deptno=:v1
        6546          1


SQL> alter system flush shared_pool;

 

시스템이 변경되었습니다.

 

SQL> select sql_text,SHARABLE_MEM,EXECUTIONS
  2        from v$sqlarea
  3       where sql_text like 'select empno,ename from emp where%';

 

SQL_TEXT
--------------------------------------------------------------------------------
SHARABLE_MEM EXECUTIONS
------------ ----------
select empno,ename from emp where deptno=30
        1461          0

 

scott 창에서

SQL> select empno,ename from emp where deptno=10;


SQL> /

SQL_TEXT
--------------------------------------------------------------------------------
SHARABLE_MEM EXECUTIONS
------------ ----------
select empno,ename from emp where deptno=30
        1461          0

select empno,ename from emp where deptno=:"SYS_B_0"
       11873          1


scott 창에서

SQL> select empno,ename from emp where deptno=20;

SQL> /

SQL_TEXT
--------------------------------------------------------
SHARABLE_MEM EXECUTIONS
------------ ----------
select empno,ename from emp where deptno=30
        1461          0

select empno,ename from emp where deptno=:"SYS_B_0"
       11873          1


문제) 다시 exact   로 바꾸고 실습하여라 !!!


SQL> alter system set cursor_Sharing=exact;

 

시스템이 변경되었습니다.

SQL> select sql_text,SHARABLE_MEM,EXECUTIONS
  2             from v$sqlarea
  3            where sql_text like 'select empno,ename from emp wh

 

SQL_TEXT
------------------------------------------------------------------
SHARABLE_MEM EXECUTIONS
------------ ----------
select empno,ename from emp where deptno=10
        6705          1

select empno,ename from emp where deptno=30
        1461          0

select empno,ename from emp where deptno=:"SYS_B_0"
       11873          2


SQL>
SQL> /

 

SQL_TEXT
------------------------------------------------------------------
SHARABLE_MEM EXECUTIONS
------------ ----------
select empno,ename from emp where deptno=10
        6705          1

select empno,ename from emp where deptno=20
        6725          1

select empno,ename from emp where deptno=30
        1461          0

select empno,ename from emp where deptno=:"SYS_B_0"
       11873          2

 

☞   4-17           실습

 

****************  테이블과 뷰만들어서 파싱확인하기 ****************

scott1
테이블 생성 및 뷰 생성
 SQL> create table abc
   2  (a1 number, a2 number);

 Table created.

 SQL> insert into abc values(111,111);

 1 row created.

 SQL> commit;

 Commit complete.

 SQL> create view abcvw
   2  as
   3  select a1+a2 summun
   4  from abc;

 View created.

scott2
테이블 뷰 실행
 SQL> select * from abcvw;

     SUMMUN
 ----------
        222

scott1
테이블 드랍
 SQL> drop table abc;

 Table dropped.

internal
 SQL> ed
 Wrote file afiedt.buf

   1  select sql_text,SHARABLE_MEM,EXECUTIONS, INVALIDATIONS
   2  from v$sqlarea
   3* where sql_text like 'select * from abcvw%'
 SQL> /

 SQL_TEXT                            SHARABLE_MEM EXECUTIONS INVALIDATIONS
 ----------------------------------------------- -----------------------
 select * from abcvw   866     1           1

scott2
테이블 뷰 쿼리
 SQL> select * from abcvw;
 select * from abcvw
        *
 ERROR at line 1:
 ORA-04063: view "SCOTT.ABCVW" has errors

scott1
다시 테이블 생성
 SQL> create table abc
   2  (a1 number, a2 number);

 Table created.

 SQL> insert into abc values(111,111);

 1 row created.

 SQL> commit;

 Commit complete.

scott2
뷰 실행(다시 실행이 됨)
 SQL> select * from abcvw;

     SUMMUN
 ----------
        222

internal

 SQL> /

 SQL_TEXT                            SHARABLE_MEM EXECUTIONS INVALIDATIONS
 ----------------------------------- ------------ ---------- -------------
 select * from abcvw                         5718          2             1

 

☞   4-20            실습

 

select shared_pool_size_for_estimate as pool_size, estd_lc_size, estd_lc_time_saved
   from v$shared_pool_advice;

 

 

SHARED_POOL_SIZE_FOR_ESTIMATE NUMBER :   Shared pool size for the estimate (in megabytes)

 

ESTD_LC_SIZE NUMBER:        Estimated memory in use by the library cache (in megabytes)

 

ESTD_LC_TIME_SAVED NUMBER

 

Estimated elapsed parse time saved (in seconds), owing to library cache memory objects being found in a shared pool of the specified size. This is the time that would have been spent in reloading the required objects in the shared pool had they been aged out due to insufficient amount of available free memory

 

☞   4-25       실습

 

■ V$SQL_PLAN

- Oracle9i 부터 새롭게 추가된 기능
- SQL문이 실행되면서 작성된 실행계획이 Shared Pool Area에 저장됨.

SQL>connect system/manager
SQL>grant dba to scott ;
SQL>connect scott/tiger
SQL>select * from dept ;
SQL>select sql_text , hash_value , address
        from v$sqlarea ;

SQL_TEXT            HASH_VALUE ADDRESS
------------------- ---------- ----------
select * from dept     3015709834   04165C60

SQL>select id, lpad(' ',depth)||operation operation , options , object_name,optimizer,cost
        from v$sql_plan
        where hash_value = &1 and address='&2'
        start with id=0
        connect by ( prior id = parent_id and prior hash_value = hash_value
                     and prior_child_number = child_number)
        order  siblings by id, position;

       &1 :  3015709834 (HASH_VALUE )
       &2 :  04165C60   (ADDRESS)

   ID     OPERATION                  OPTIONS   OBJECT_NAME    OPT    COST
  ----  ----------------------  ----------- ---------------   ------   ------
   0      SELECT STATEMENT                                              CHO
   1     TABLE ACCESS              FULL            DEPT


  <=  또는, set autotrace on 사용으로 SQL문 실행시 파싱단계에서 옵티마이저가 작성한 실행계획
        을 참조할 수 있다.

 

 

 

☞   4- 26 실습

 

SQL> show parameter shared_pool_size

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
shared_pool_size                     big integer 50331648

 

SQL> select sum(sharable_mem)
       from  v$db_object_cache;

 

SUM(SHARABLE_MEM)
-----------------
           331406


☞   4-30 ~ 4-32           실습

 

 show parameter shared

 

select p.value/r.value * 100 "reserved radit"
     from v$parameter p, v$parameter r
     where p.name = 'shared_pool_reserved_size'
    and r.name = 'shared_pool_size';

 

select * from v$db_object_cache
 where sharable_mem  > 10000
 and ( type='PACKAGE' or  type='PACKAGE BODY' or
          type='FUNCTION' or type='PROCEDURE' )
and kept='NO';


@d:\oracle\ora92\rdbms\admin\dbmspool.sql

 

 desc dbms_shared_pool

 

 execute dbms_shared_pool.keep('dbms_sql');

 

select * from v$db_object_cache
 where sharable_mem  > 10000
 and ( type='PACKAGE' or  type='PACKAGE BODY' or
          type='FUNCTION' or type='PROCEDURE' )

 

☞   4-30 ~ 4-32           실습

 

SQL> declare x number;
      begin x :=5;
     end;
     /

PL/SQL 처리가 정상적으로 완료되었습니다.

SQL>
SQL> declare /* keep_me */ x number;
     begin x := 5;
     end;
     /

PL/SQL 처리가 정상적으로 완료되었습니다.

SQL> select address, hash_value
      from v$sqlarea
      where command_type=47
      and sql_Text like '%keep_me%';

ADDRESS  HASH_VALUE
-------- ----------
669841E4 4215866029

 execute dbms_shared_pool.keep('669841E4,4215866029','c');


select distinct name, sharable_mem, loads
     from v$db_object_cache
   where name like '%keep_me%';

 

DBMS_SHARED_POOL을 이용한 KEEP

 

Shared Poll에 크기가 큰 프로그램을 KEEP하기 위해서는 아래에 있는 것처럼 DBMS_SHARED_POOL Package를 이용 할 수 있습니다.

 

SQL> @C:\oracle\ora92\rdbms\admin\dbmspool.sql

 

패키지가 생성되었습니다.


권한이 부여되었습니다.


뷰가 생성되었습니다.


패키지 본문이 생성되었습니다.

 

SQL> @C:\oracle\ora92\rdbms\admin\prvtpool.plb

 

뷰가 생성되었습니다.


패키지 본문이 생성되었습니다.

 

SQL> grant execute on dbms_shared_pool to scott;

 

권한이 부여되었습니다.

 

Object를 KEEP하는 방법은 다음과 같습니다.

 

Procedure,Function,Package : exec dbms_shared_pool.keep(‘pname’,’p’)
Trigger : exec dbms_shared_pool.keep(‘tr_emp’,’r’)
Sequence : exec dbms_shared_pool.keep(‘seq_empno,’q’)


SQL문은 아래와 같은 방법으로 KEEP 합니다.

 

예를들어 select empno, ename, sal from emp where deptno = ‘20’ 라는 SQL문장을 Library Cache안의 Shared Cursor 부분에 KEEP하기 위해서는 아래처럼 하면 됩니다…

 

SQL> conn scott/tiger


연결되었습니다.

 

SQL> select empno, ename, sal from emp where deptno = 20;

 

     EMPNO ENAME             SAL
---------- ---------- ----------
      7369 SMITH             800
      7566 JONES            2975
      7788 SCOTT            3000
      7876 ADAMS            1100
      7902 FORD             3000

 

SQL> conn / as sysdba


연결되었습니다.

 

SQL> select address, hash_value from v$sqlarea
  2  where sql_text = 'select empno, ename, sal from emp where deptno = 20';

 

ADDRESS  HASH_VALUE
-------- ----------
7856AC4C 1137127237   <- 원하는 SQL문장에 대한 주소와 해시 값

 

아래 명령으로  KEEP 합니다.

 

SQL> exec dbms_shared_pool.keep('7856AC4C, 1137127237','c');

 

PL/SQL 처리가 정상적으로 완료되었습니다.

 

Object의 KEEP 상태는 다음으로 체크 가능 합니다.

 

SQL> select distinct name, sharable_mem, loads
     from v$db_object_cache
     where name like '%emp%'
     and kept = 'YES';

 

NAME                                      SHARABLE_MEM      LOADS
------------ ----------------------------------------------
select empno, ename, sal from emp where deptno = 20   1469          1

 

또는 exec dbms_shared_pool.sizes(0)로 확인 가능 합니다. 이 sizes라는 procedure는 제한된 사이크 이상의 keep된 Object를 나타내 줍니다.

 

SQL> set serveroutput on size 2000


SQL> exec dbms_shared_pool.sizes(0)  -> buffer overflow가 나더라도 pin시킬(KEEP할) SQL문장을 찾을 수는 있습니다.

 

각 Object를 Shared Pool에 유지하던 것을 해제 할 때는 아래의 unkeep 프로시저를 이용 합니다.

 

SQL> exec dbms_shared_pool.unkeep('7856AC4C, 1137127237','c');

 

PL/SQL 처리가 정상적으로 완료되었습니다.

 

SQL> select distinct name, sharable_mem, loads
  2  from v$db_object_cache
  3  where name like '%emp%'
4  and kept = 'YES';

 

결과가 없겠죠…


 

☞  자주 사용되는 PL/SQL 블록을 캐싱한다.

- PL/SQL(프로시저,함수,패키지,트리거) 블록들은 너무 커서 실행시 마다 라이브러리 캐시영역
   에 로드되었다가 다시 제거되는 현상이 반복 --> 라이브러리 캐시영역의 단편화 현상 발생
- PL/SQL 블록 , SEQUENCE 등을 라이브러리 영역에 캐싱할 수 있도록 DBMS_SHARED_POOL
  패키지 제공.

SQL> select name,type,kept
         from v$db_object_cache
        where type in ('PACKAGE','PROCEDURE','TRIGGER','PACKAGEBODY');

NAME                      TYPE                 KEPT
------------------- ---------            ------
                                                             <= 캐싱된 PL/SQL 블록 정보가 없다
SQL>connect scott/tiger
SQL>create or replace procedure check_swan   <= 샘플 Procedure 생성
         (  v_emp_no in emp.empno%type )
          is
          begin
             delete from emp where empno = v_emp_no ;
        end check_swan ;
       /
  
SQL>execute DBMS_SHARED_POOL.KEEP('CHECK_SWAN')
                                <= 해당 프로시저를 공유 풀 영역에 상주.

SQL> select name,type,kept
         from v$db_object_cache
        where type in ('PACKAGE','PROCEDURE','TRIGGER','PACKAGEBODY');

NAME                      TYPE                 KEPT
------------------- -------------       ------
CHECK_SWAN          PROCEDURE          Y   <= 해당 프로지셔 캐싱

SQL>execute DBMS_SHARED_POOL.UNKEEP('CHECK_SWAN')


SQL> select name,type,kept
         from v$db_object_cache
        where type in ('PACKAGE','PROCEDURE','TRIGGER','PACKAGEBODY');

NAME                      TYPE                 KEPT
------------------- -------------       ------
CHECK_SWAN          PROCEDURE          N   <= 해당 프로지셔 캐싱 해제

 

 

 

 

 

☞  4-41 실습

 

 

아래의 쿼리를 이용하여 가장 빈번하게 사용되는 오브젝트를 찾을 있다.

select cache#, type, parameter, gets, getmisses, modifications mod 
from   v$rowcache
where  gets > 0
order by gets;

CACHE# TYPE        PARAMETER                GETS  GETMISSES    MOD
------ ----------- ------------------ ---------- ---------- ------
     7 SUBORDINATE dc_user_grants        1615488         75      0
     2 PARENT      dc_sequences          2119254     189754    100
    15 PARENT      dc_database_links     2268663          2      0
    10 PARENT      dc_usernames          7702353         46      0
     8 PARENT      dc_objects           11280602      12719    400
     7 PARENT      dc_users             81128420         78      0
    16 PARENT      dc_histogram_defs   182648396      51537      0
    11 PARENT      dc_object_ids       250841842       3939     75


 

row cache 튜닝은 매우 제한적이다. 최상의 솔루션은 V$ROWCACHE 결과를 기반으로 딕셔너리 접근을 줄이는 것이다. 예를 들어, 만일 시퀀스가 문제라면, 시퀀스를 캐슁하는 것을 고려할 있다. 여러 개의 테이블 조인을 포함하는 중첩된 뷰는 래치 경합을 증가시키게 된다. 일반적인 대안은 단순히 SHARED_POOL_SIZE 증가하는 것이다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

기타>

 

 

 


LIBRARY CACHE LOCK WAIT EVENT가 나타날 때의 해결방법
====================================================


PURPOSE
-------
v$session_wait event 에 'library cache lock'이 발생하면서 session이
waiting 되는 경우가 있다. 오랫동안 이 현상이 지속될 경우 어떤 session이
이 library cache lock 을 갖고 있는지 확인해 볼 수 있다.

Explanation
-----------
v$session_wait view에 'library cache lock'이 나타날 수 있는 경우가
어떠한 것이 있는 지 알아보자.

예를 들어 다음과 같은 alter table 문장의 경우를 살펴보자.
 
 ALTER TABLE x MODIFY (col1 CHAR(200));

X 라는 Table의 row가 많다면 위의 문장으로 인해서 모든 row의 값이
200 bytes로 update되어야 하므로 굉장히 오랜 시간이 걸리게 된다.
이 작업 중에는 Table에 dml이 실행되어도 waiting되는 데, 이런 때에
'library cache lock' 이라고 나오게 된다.

또 package가 compile 되는 중에는 다른 user가 같은 package 내의
procedure나 function 등을 실행시켜도 waiting이 걸리면서 library cache
lock 이나 library cache pin event가 나타난다.

이 library cache lock 을 잡고 있는 session을 확인해 보자.

 

1. waiting session의 session address 확인


 library cache lock으로 waiting하고 있는 session의 sid를 찾아서
그 session address - v$session의 saddr column 을 확인한다.


2. 다음과 같은 sql로 해당 library cache lock을 잡고 있는 session을
확인할 수 있다.

 아래의 SQL 중에서 'saddr_from_v$session' 부분에 위의 1번에서 찾은
Waiting session의 saddr 값을 입력한다.
단, 아래의 sql은 반드시 sys 또는 internal user에서 실행해야 한다.

 

 SELECT SID,SERIAL#,USERNAME,TERMINAL,PROGRAM
 FROM V$SESSION
 WHERE SADDR in
  (SELECT KGLLKSES FROM X$KGLLK LOCK_A
   WHERE KGLLKREQ = 0
     AND EXISTS (SELECT LOCK_B.KGLLKHDL FROM X$KGLLK LOCK_B
                 WHERE KGLLKSES = 'saddr_from_v$session' /* BLOCKED SESSION */
                 AND LOCK_A.KGLLKHDL = LOCK_B.KGLLKHDL
                 AND KGLLKREQ > 0)
  );


3. 2번에서 확인한 blocking session에 의해 waiting하고 있는 session들도
확인할 수 있다. 2번에서 찾은 session의 saddr 값을 다음 sql에 대입하여
찾을 수 있다.

 

 

 SELECT SID,USERNAME,TERMINAL,PROGRAM
 FROM V$SESSION
 WHERE SADDR in
  (SELECT KGLLKSES FROM X$KGLLK LOCK_A
   WHERE KGLLKREQ > 0
     AND EXISTS (SELECT LOCK_B.KGLLKHDL FROM X$KGLLK LOCK_B
                 WHERE KGLLKSES = 'saddr_from_v$session' /* BLOCKING SESSION */
                 AND LOCK_A.KGLLKHDL = LOCK_B.KGLLKHDL
                 AND KGLLKREQ = 0)
  );


4. blocking session이 왜 오래 걸리는 것인지, v$session_wait 를 다시
확인하거나 실행하고 있는 sql 문장이나 object 등을 v$sql view 등을 확인
해 보아야 한다. 작업이라면 종료될 때까지 기다릴 수 있겠지만, 비정상적인
경우 또는 waiting session을 위해서는 다음과 같이 kill 할 수도 있다.

 

 

 alter system kill session 'SID, SERIAL#';

반응형
Posted by [PineTree]
ORACLE/TUNING2011. 11. 23. 00:12
반응형

SHARED POOL SIZE의 계산방법
==============================
PURPOSE
---------
다음은 ORACLE DATABASE 의 SHARED POOL SIZE를 계산하는 방법에 대하여 알아보기로 한다.

Explanation
------------
오라클 instance를 background process + SGA라고 말할 때 처음 instance가 기동되면 SGA가 할당된다. 이 때 이 SGA를 구성하는 메모리 영역은 크게 3부분으로 구성된다고 할 수 있다.
- Shared pool, Redo log buffer, DB buffer cache.


여기서는 SGA를 구성하는 shared pool의 size를 시스템에 맞게 산출하는 방법에 대해서 알아본다.
Shared pool 영역 구성은 MTS 방식으로 접속된 session의 PGA, Shared SQL area 그리고 dynamic하게 할당되는 data structure로 구성된다.


1. Shared Pool
Shared pool은 ?/dbs/initSID.ora(parameter file)의 SHARED_POOL_SIZE라는 parameter로 그 크기를 지정하는데 default값은 3.5M를 갖게 된다.
일반적으로 shared pool이 얼마나 사용되는가 하는 문제는 application dependent하므로 각

application을 조사하는 게 필요하다.
시스템에서 필요로 하는 크기를 검사하기 위해 아주 큰 크기로 parameter file에 지정하여 dynamic하게 할당되는 SGA가 충분히 큰 값을 갖게 한 후, 검사가 끝난 다음 아래에서 계산된 size로
변경 해 주도록 한다.


2. 계산 공식
Session 당 최대 메모리 사용량(Max Session Memory)
* 동시 접속하는 User의 수
+ Shared SQL 영역으로 사용되는 메모리 양
+ Shared PLSQL을 위해 사용하는 메모리 영역
+ 최소 30%의 여유 공간
= Minimum Shared Pool

3. 계산 예제
(1) 적당한 user session에 대한 session id를 찾는다.

SVRMGR> select sid from v$process p, v$session s
where p.addr=s.paddr and s.username=''SCOTT'';
SID
----------
29
1 rows selected.


(2) 이 session id에 대한 maximum session memory를 찾는다.

SVRMGR> select value from v$sesstat s, v$statname n
where s.statistic# = n.statistic#
and n.name = ''session uga memory max''
and sid=29;
VALUE
-----------
273877
1 rows selected.

(3) Total shared SQL area를 구한다.

SVRMGR> select sum(sharable_mem) from v$sqlarea;
SUM(SHARAB
------------------
8936625
1 row selected.

(4) PLSQL sharable memory area를 구한다.

SVRMGR> select sum(sharable_mem) from v$db_object_cache;
SUM(SHARAB
------------------
4823537
1 row selected.


(5) Shared pool size를 계산한다.

274K shared memory * 400 users
+ 9M Shared SQL Area
+ 5M PLSQL Sharable Memory
+ 60M Free Space (30%)
= 184M Shared Pool

이 예제에서는 Shared pool의 size는 184M가 적당하다고 할 수 있다.

4. Shared Memory 부족 (ORA-4031)에 대한 대처 Ora-4031이 발생하는 원인은 2가지이다. 첫째 절대적으로 shared pool size가 작아서 나는 경우와, 둘째로 memory는 있으나 적재하려 하는

PL/SQL package가 너무커서 연속된 shared pool영역을 점유하지 못하는 경우가 있다.
만일 첫번의 경우라면 적당한 계산 과정으로 계산하여 parameter file에서 SHARED_POOL_SIZE를 늘려주고 ,두 번째 경우라면 다음과 같은 방법으로 에러를 피해 갈 수 있다.
- "Sys.dbms_shared_pool.keep" procedure사용.


[참고] 위 package를 사용하려면 ?/rdbms/admin/dbmspool.sql,
prvtpool.plb를 수행시켜 package를 create시킨 후 사용한다.


1. sga_target

이 parameter는 사용자가 원하는 크기만큼 sga를 지정하면 oracle kernel이 알아서(process수 etc)
shared_pool, db_cache_size등을 동적으로 할당하게 됩니다.
그냥 단순히 원하는 size만 지정하면 됩니다.
사용 예)
init.ora 에
sga_target = 300m
변경은 alter system set sga_target = 200m; 이런식으로 하면 됩니다만..
sga_target < sga_max_size입니다. sga_max_size는 oracle 10g에서도 변경 불가 입니다.

2. OLTP 속성에 관련된 parameter(shared_pool_size , db_cache_size)
sga_target , db_cache_size, shared_pool_size는 동적으로 크기를 변경할 수 있습니다.
단,db_cache_size + shared_pool_size <= sga_target 여야 합니다.
또한, sga_target < sga_max_size(변경불가) 입니다.
만약 sga_target = 300m로 지정하고

alter system set shared_pool_size = 100m;
alter system set db_cahce_size = 150m;

이렇게 하면 원하는 크기만큼 설정이 됩니다.

물론, shared_pool_size와 db_cache_size를 지정하지 않으면 오라클이 알아서(?)
내부적으로 shared_pool_size와 db_cache_size를 할당합니다.


가) sga_target만 설정한 경우
. sqlplus 에서 "show parameter sga_target" --- 지정된 값
. sqlplus 에서 "show parameter shared_pool_size" -- 0
. sqlplus 에서 "show parameter db_cache_size" -- 0

. alter system set sga_target = 200m; 으로 변경하면
. sqlplus 에서 "show parameter sga_target" --- 200m
. sqlplus 에서 "show parameter shared_pool_size" -- 0
. sqlplus 에서 "show parameter db_cache_size" -- 0

나) sga_targe=300m, shared_pool_size, db_cache_size를 지정한 경우
. sqlplus 에서 "show parameter sga_target" --- 지정된 값
alter system set shared_pool_size = 100m;
alter system set db_cahce_size = 150m;

. sqlplus 에서 "show parameter shared_pool_size" -- 100m
. sqlplus 에서 "show parameter db_cache_size" -- 150m

3. Batch 속성에 관련된 parameter(pga_aggregate_target)
Batch 속성을 갖는 DB는 주로 sorting 작업을 많이 하기 때문에 pga 영역의 확보가 절대적으로 필요합니다.
따라서 alter system set pga_aggregate_target = 1000m; 등등으로 설정하면 됩니다.

4. 그러면 얼만큼 메모리를 할당하면 될까요?
가) 일반적으로 OLTP인경우
SGA (65%) + PGA (15%) + O/S Overhead (20%)
예를 들어 전체 메모리가 10G 인경우
SGA ( 6G) , PGA( 2G ), O/S (2G)

나) 일반적으로 BATCH인경우
SGA (30%) + PGA (50%) + O/S Overhead (20%)
예를 들어 전체 메모리가 10G 인경우
SGA ( 3G) , PGA( 5G ), O/S (2G)

5. 그러면 4.에서 권고한 만큼 메모리를 할당/재할당 해야 하나요?
- 그건 그때 그때 달라요.. 경험이 필요하겠죠
원칙은 오라클에 가급적 많음 메모리를 할당하되, page나 swap이 빈번하게 발생하면 않되겠쬬!!!!!


반응형

'ORACLE > TUNING' 카테고리의 다른 글

SQL 실행 계획 확인방법  (0) 2012.01.10
SGA/PGA 튜닝 시 고려(검토)할 오라클 factor  (0) 2011.12.16
OWI를 활용한 shared pool 진단 및 튜닝  (0) 2011.11.23
Oracle Session별 Trace 생성 방법  (0) 2011.10.21
SQL TRACE  (0) 2011.10.21
Posted by [PineTree]
ORACLE/TUNING2011. 11. 23. 00:05
반응형

OWI를 활용한 shared pool 진단 및 튜닝

 

아직도 Shared pool 설정에 어려움을 느끼십니까?

 

작성자 : 한민호(blubeard@nate.com)

 

필자가 Oracle Internal에 관심을 가지게 된 것은 얼마 되지 않지만 공부를 하면서 이렇게 자료를 만들어 정리를 해보는 것도 좋은 경험이 되고 여러 사람들과 지식을 공유하고 싶었기 때문에 OKM에 기고하게 되었다.

SGA에서 shared pool만큼 사이즈를 설정하기 어려운 Parameter가 없다. 그리고 이 shared pool의 크기는 너무 커도, 너무 작아도 문제가 된다., 얼마나 적절히 설정하느냐에 따라 DB의 성능을 좌우하게 된다. Parameter만 잘 설정해도 성능이 좋아진다니 이렇게 편하고 좋은 튜닝 방법이 어디 있을까 하는 생각도 든다. 하지만 shared pool의 크기를 아무 지식과 진단 없이 적절히 설정하기란 여간 까다로운 일이 아닐 수 없다. 특히 Row cacheLibrary cache는 크기를 각각 설정하는 것이 불가능하기 때문에 초보자에겐 이런 것들이 어려움으로 다가올 수 있다. Shared pool을 자세히 알아 봄으로써 그러한 걱정들을 이번 기회에 덜 수 있다면 훌륭한 DBA가 되는데 도움이 되리라 생각된다. 이에 Shared Pool을 설정함에 있어 진단의 지표로 OWI를 사용할 것이다.

 

- Wait Event의 중요성

 Programming을 해본 사람이라면 동기화 문제에 대해 매우 잘 알고 있을 것이다. Oracle역시 수많은 Transaction에 의해 작업이 되기 때문에 이 때 발생하는 동기화 문제들을 해결하기 위해 수 많은 Latch, Lock, Pin을 사용하고 있다. 이 동기화란 것은 Serial한 작업이기 때문에 성능에 막대한 영향을 주게 된다. Wait Event는 이러한 동기화 작업에 있어서 Critical Section에 들어가지고 못하고 대기하는 작업들의 대기시간 동안 발생하는 이벤트이다. 이 때문에 Wait Event 발생을 줄이는 것은 중요한 일이고 이를 잘 분석하여 Tuning하는 것은 매우 효과적인 방법인 것이다. 그럼 이제 Shared PoolWait Event의 관점에서 진단하고 분석해보기로 하겠다.

 

- Shared pool의 목적

Shared pool에 대해 간략히 설명을 해보자면 shared pool의 목적은 실행된 Cursor를 공유하여 CPUmemory를 효율적으로 사용하는 데 있다. CursorSQL의 경우 실행할 때 필요한 실행계획 같은 실행 정보를 담고 있는 SGA상에 할당된 Heap Memory를 말한다. 물론 공유 할 수 있는 것들은 다양하다. 공유할 수 있는 정보들을 나열하자면 SQL구문, 실행계획, PL/SQL소스와 그것들의 실행정보, table, view 같은 object 등이 있다. 이것들을 공유한다면 동일한 PL/SQL이나 SQL을 실행함에 있어 매번 실행계획을 만들며 hard parsing이 일어나는 부하를 예방할 수 있다.

 

- Shared pool의 구성요소

shared pool을 구성하고 있는 구성요소에 대해 알아보겠다. 우선 shared pool의 구성요소는 4가지로 나뉜다. Process목록, Session목록, Enqueue목록, Transaction목록 등이 할당된 Permanent AreaSQL문을 수행하는데 필요한 모든 객체 정보를 관리하는 Library cache, dictionary 정보를 관리하는 Row Cache, 그리고 마지막으로 동적 메모리 할당을 위한 공간인 Reserved Area로 나눌 수 있다.

 

- Heap Manager를 통한 메모리 관리

메모리에 대한 할당 및 해제 작업은 Heap Manager를 통해 동적으로 관리가 된다.Heap Manager에 대해 간략히 알아보면 Top-levelHeap과 그 하위에 여러 개의 Sub-Heap을 포함하는 구조를 이루고 있다.Heap은 또한 linked list구조의 Extent들로 구성이 되어 있으며 Extent는 여러 개의 chunk로 구성되어있다. 실제적으로 chunk의 사용 현황에 대해 알고 싶다면 X$KSMSP라는 View를 통해 관찰 할 수 있을 것이다.

 

- Chunk의 관리

Chunk4가지 상태로 관리가 된다.4가지 상태는 Free, Recreatable, Freeable, Permanent. 이러한 chunk들의 상태에 따라 linked list가 구성되는 것이다. 상태의 이름만으로도 그것이 어떤 상태인지 알 수 있을 것이다. 더 정확히 설명 하자면 Free는 즉시 사용 가능한 상태를 말한다.Free 상태의 chunk들로 묶여 있는 linked listfree list인 것이다. 구체적으로 설명하면 이것은 255개의 bucket이 있고 각 bucketfree chunk들이 linked list구조로 연결되어있다. 이때 bucket은 각각의 정해진 기준의 크기 이하의 chunk들로만 구성되어 있다. 이러한 이유로 bucket이 아래로 갈수록 chunk들의 크기가 크다. Recreatable은 재생성 가능한 상태이다. 뒤에서 다시 설명하겠지만 이것은 unpinned(현재 사용되고 있지 않은)일 때 재사용이 가능하다. 쉽게 말하자면 이것은 사용이 되었었지만 다시 사용될 확률이 낮아져서 재사용이 가능한 상태가 된 것이며, 현재 사용 중이 아니라면 chunk를 재사용할 수 있도록 이러한 상태의 chunk를 묶어 LRU list로 관리한다. (관련 뷰 : X$KGHLU) 그리고 Freeablesession이나 call 동안에만 필요한 객체를 저장하고 있는 상태이며 이는 session등이 금방 끊길 수도 있기 때문에 chunk가 필요할 때 할당의 대상이 되지는 못한다. Permanent는 말 그대로 영구적인 객체를 저장하고 있는 상태이며 이것 역시 사용할 수 없는 chunk.

실제 Heap Dump를 이용하면 R이 앞에 붙어서 상태가 정의 되어 있는 것을 볼 수 있는데 이것은 SHARED_POOL_RESERVED_SIZEParameter를 통해 발생한 chunk들이다.chunk도 적절히 사용하면 매우 중요한 튜닝 요소가 될 수 있다. 이것에 대해 oracle 매뉴얼에서는 PL/SQL block이 많이 사용되는 경우를 예로 들고 있다., 이것은 large chunk를 위해 할당된 공간인 것이다. Parameter를 정해 주지 않는다면 설정된 shared_pool_size5%default value로 분류된다. Steve AdamsOracle Internal이나 매뉴얼에서도 5000byte 이상의 큰 object를 위한 공간이라고 설명한다. 이는 large chunk가 요구되지 않는다면 굳이 설정할 필요가 없다는 말도 되는 것이다. 이러한 튜닝 요소에 초점을 맞추어 설정하면 되는 parameter인 것이다. 이것들 역시 linked list로 관리되며 명칭은 Reserved Free list라고 부른다.

(아래 그림 1을 참조한다면 이해하는 데에 도움이 될 것이다.)

[그림 1] Shared Pool Heap 구조(출처 : Advanced OWI in Oracle 10g / ㈜엑셈)

 

정리를 해보자면 chunk는 사용할 수 있는 것과 없는 것으로 나눌 수 있다. 그 중에 실제 chunk 할당 과정에서 latch경합을 벌여 Wait Event가 발생하기 때문에 free listLRU list에서 관리되고 있는 chunk들에 주목을 할 필요가 있을 것이다. 왜냐하면 운영 시 peak time때의 할당된 chunk의 총 크기가 곧 shared poolsize를 적절히 결정하는 데에 중요한 역할을 하기 때문이다. 이것에 대한 설명은 Wait Event의 발생과 연관 지어 이야기 해 보겠다.


- Shared Pool
의 관리

Chunk를 할당하는 과정에서 반드시 필요한 것이 shared pool latch의 획득이다. 하지만 이러한 shared pool latch는 아쉽게도 shared pool당 단 1개 밖에 존재하지 않는다. 이것은 즉, chunk를 동시에 할당 받아야 할 상황이라면 이것을 획득하는 과정에서 경합을 벌이게 된다는 의미이다. 무엇 때문에 이렇게 shared pool latch 수를 적게 만들어 놓았는지 정확히 알 수는 없지만 여러 개를 만들어 놓았다면 역시나 동기화 문제를 관리하는데 있어 어려움이 있기 때문이 아닐까 싶다. 다행히도 Oracle 9i부터는 Hidden Parameter_KGHDSIDX_COUNT를 이용하여 하나의 shared Pool7개까지의 Sub-Pool로 나누어 관리하는 것이 가능해졌다. 그리고 더 반가운 소식은 각각의 Sub-pool당 독자적인 free list, LRU list, shared pool latch를 가짐으로 인해 부족했던 자원에 대한 경합을 그나마 감소시킬 수 있게 되었다. 그러나 경합은 감소했을지 몰라도 CPU의 개수나 SHARED_POOL_SIZE가 충분히 크지 않다면 ORA-4031에러의 발생위험이 1개의 shared pool로 관리됐을 때보다 더 높다는 것이다. 그래서 권장하는 방법이 CPU 4개에 SHARED_POOL_SIZE250m이상일 때 Sub-pool을 사용하는 것이다. 한 때는 하나의 Sub-pool에 할당 가능한 chunk공간이 없으면 다른 Sub-pool에 사용 가능한 free chunk가 있음에도 찾지 못했던 버그도 있었다. shared pool latch에 대해 좀 더 알아보자면 실제적으로 shared pool latch를 소유하는 시간이 shared pool latch를 대기하게 하는 중요한 이유이다. 때문에 latch를 획득한 후에 일어나는 작업들을 알면 경합의 포인트를 알 수 있을 것이다.

 

 - Chunk의 할당과정

Shared pool latch를 획득하게 되면 우선 free chunk를 찾기 위해 free list를 탐색한다. 그리고 적절한 free chunk가 있다면 할당을 받지만 없다면 LRU list를 탐색하게 된다. 이것마저도 찾지 못한다면 Reserved Free List를 탐색하고 이것 역시 실패하면 Spare Free Memory를 탐색하게 된다. 이 모든 과정이 실패가 되었을 때 ORA-4031에러가 발생하게 되는 것이다. 이 과정에서 할당을 받게 된다면 딱 필요한 크기만 할당을 받고(split) 나머지는 다시 free list에 등록이 되기 때문에 free list가 할당이 된다고 해서 반드시 짧아지는 것은 아니다. 그리고 적절한 chunk를 찾기 위해 위에서와 같이 여러 과정은 거치지만 이 과정은 생각보다 매우 빠른 시간 안에 이루어진다. 하지만 이것들이 다수의 작업이 된다면 경합에 대한 wait time은 피부로 느껴질 것이다. 여기서 이제껏 언급이 없었던 Spare Free Memory에 대해 궁금해하는 분이 많을 꺼 같아 간단하게 설명하자면(이 내용은 Steve AdamsOracle Internal에 내용이 있다) instancestart up 되었을 때 shared pool size에 정해진 크기의 절반만이 shared pool에 할당된다. 이것은 성능을 극대화 하는데 에도 연관이 있으리란 생각이 든다. Chunk의 수가 줄면 그 만큼 free list가 짧아지기 때문에 그에 대한 탐색시간도 짧아지고 shared pool latch의 소유 시간 역시 짧아지기 때문에 메모리를 숨겨놓지 않았을까 생각된다. 위의 과정들을 미루어 짐작해볼 때 shared pool latch의 소유시간은 free list의 길이와 얼마나 빨리 적절한 chunk를 찾느냐에 따라서 결정된 다는 것을 알 수 있을 것이다. 그럼 free list의 길이가 길어지는 것은 어떠한 경우 일까? 바로 그것은 chunk split가 다량으로 발생하여 단편화(fragmentation) 되었을 때이다. 이러한 경우 free list의 길이가 길어지게 되는 것이다. 단편화는 hard parsing에서 일어나는 것인데 hard parsing에 대해 모르는 독자들을 위하여 간단히 설명하면 처음 실행하는 SQL문이 있다면 이것에 대한 실행정보를 저장하고 있는 Heap Memory 할당이 필요한데 이 Heap이 바로 chunk인 것이다. 이러한 실행계획을 만들고 chunk에 할당하는 과정은 매우 부하가 있기 때문에 hard parsing이라고 이름 붙여진 것이다. 이런 과도한 단편화로 인해 shared pool latch의 경합만 가중 시키는 것이 아니다.chunk 할당이 요구되는 hard parsing이 이루어 질 때 적절한 free chunk를 찾지 못하여 ORA-4031에러를 유발하게 된다.

 

- Shared Pool Size 설정

지금까지 설명했던 것들을 가지고 shared pool size에 대해 결론을 내 보면, 첫째로, memory가 무조건 크다는 생각으로 shared pool을 늘리면 안 된다고 볼 수 있다. 이것은 오히려 free list의 길이만 늘어나게 되기 때문이다. 그리고 V$SGASTAT를 통해 확인한 shared poolfree memory가 작다고 해서 SHARED_POOL_SIZE를 늘려서는 안 된다. Free memory는 단지 free chunk의 합이기 때문이다. 이는 즉 LRU list, reserved list, spare memory도 있기 때문에 크게 문제가 되는 것은 아니라는 말이다. 지금까지 설명한 것을 고려해 본다면 적절한 크기를 정하는 데는 매우 도움이 될 것이다. 만약 초보 DBA라면 Oracle에서 제공하는 advice를 이용하는 것도 괜찮은 방법일 듯싶다. OEM구성을 하여 Enterprise Manager를 보면 memory tab에서 shared pool 부분의 advice버튼만 클릭하면 적절한 shared pool 크기에 대한 지침을 제공하고 있다.(그림 2를 참조하시오) 이것이 아주 정확한 척도가 되지는 못할지라도 초보 DBA에게는 매우 매력 있는 기능임에는 틀림이 없다. 이 지침은 되도록이면 peak time 이후에 이용하는 것을 권장한다.

\

[그림 2] Enterprise ManagerShared pool advice

 

Shared Pool Size를 적절히 줄이게 되면 free list 탐색시간의 감소로 인해 hard parsing에 의한shared pool latch의 경합을 줄이는 효과를 볼 수 있지만 ORA-4031에러의 위험이나 상주할 수 있는 공유 객체의 수가 줄어들어 LRU list를 자주 이용하기 때문에 오히려 부가적인 hard parsing을 발생시킬 수 있음에 유의해야 한다. 이때 오르내리는 객체가 프로시저나 패키지라면 그 부하는 상당할 것이다. 이에 대비하여 DBMS_SHARED_POOL.KEEP을 이용하여 메모리에 고정시키는 방법도 매우 유용하다. Shared poolflush해도 내려가지 않기 때문이다. Shared pool latch가 발생하는 것을 가장 줄일 수 있는 방법은 bind변수의 사용이나 CURSOR_SHARING Parameter를 설정하는 것이다. CURSOR_SHARING parameterSQL문장을 자동으로 bind변수치환을 해주는 변수이다. 위에서 언급했던 Flush Shared pool에 대하여 잠시 설명을 하고 가면 alter system flush shared_pool;이란 명령을 통해 shared poolflush 시킬 수 있다. 이 작업은 단편화된 free chunk에 대해 coalesce 작업이 이루어 지기 때문에 유용하지만 NOCACHE 옵션이 없는 sequence가 있다면 예상치 못한 gap이 생길 수도 있기 때문에 유의해야 한다.

 

 - Library Cache LatchShared Pool Latch의 관계

Shared pool을 튜닝 하는데 있어 반드시 shared pool latch 획득만이 문제가 되는 것은 아니다.  바로 shared pool latch 획득 이전에 library cache latch의 획득이 먼저 있기 때문이다. 이것을 비롯한 parsing에 대해 좀더 이해를 돕기 위해 아래의 그림 3을 참조하기 바란다.

작업

Hard Parsing

Soft Parsing

Syntax, Semantic, 권한체크

Library cache latch 획득

Library cache 탐색

LCO가 있다면 Library cache latch 해제

 

Shared Pool latch 획득

 

할당 가능한 Chunk탐색 및 Chunk할당

 

Shared Pool latch 해제

 

Parse Tree Execution Plan 생성

 

[그림 3]  parsingshared pool latchlibrary cache latch

 그림 3를 보면 알 수 있듯이 hard parsingsoft parsing 보단 부하가 큰 작업 임을 알 수 있다. 또한 library cache latchshared pool latch 획득 시점을 미루어 보아 동시에 많은 세션이 library cache latch를 획득하려고 하게 되면 이것에 대한 병목 현상으로 shared pool latch에 대한 경합은 상대적으로 줄어들 수 있을 것이란 예상도 가능하다. 그렇다면 이렇게 shared pool latch에 영향을 주는 library cache latch에 대해서도 자세히 알아볼 것이다.

 

- Library Cache의 구조와 관리

Library cache에 할당 받는 Heap memoryshared pool latch를 걸고 할당 받은 free chunk이다. 이때 Library Cache Manager(KGL)에 의해 관리되는데 이는 내부적으로 Heap Manager(KGH)를 이용하는 것이다. 이때 할당된 free chunkLCO(Library Cache Object)handle을 저장하는데 사용된다. Library Cache Memory는 크게 hash function, bucket, handle list, LCO로 구성되어 있다. 하나씩 설명을 해보면 hash functionbucket을 결정하기 위한 연산을 수행하는 함수로 보면 된다. 객체에 따라 SQL의 경우 SQL TEXT를 그대로 numeric 값으로 변환하여 bucket을 결정하고 SQL외의 객체들은 schema, object name, DB linknumeric 값으로 변환하여 bucket을 결정한다. Bucket의 성장은 LCO의 크기가 매우 많아져서 성장이 불가피할 때 성장하게 되는데 이때 대략 2배 크기의 소수로 확장하게 된다. 그리고 bucket의 초기 값은 _KGL_BUCKET_COUNT로 설정이 가능하다.

아래 그림 4, 5는 필자가 그린 handleLCO의 구조, 그리고 그것에 대한 간략한 설명이다.

 

[그림 4] Handle의 구조

[그림 5] LCO의 구조

[그림 6] Library cache 구조 (출처 : Advanced OWI in Oracle 10g / ㈜엑셈)

 

위의 그림 4, 5를 숙지하였다면 handle이 무엇이고 LCO가 무엇인지, 또 이것이 저장하는 정보에 대하여 알 수 있었을 것이라고 예상 된다. 이제 그림 6을 보면 대략적인 구조가 머리 속에 들어 올 것이다. 여기서 특징적인 것은 SQL의 경우 child table을 갖는 다는 점이고 그 child table이 저장하고 있는 실제적 자식 handleLCO는 익명 리스트로 관리되고 있다는 점이다. 물론 PL/SQL의 경우는 조금 다르다. 이것의 구조는 그림 7,8을 보면 좀더 명확히 알 수 있다.

[그림 7] SQLLCO구조

[그림 8] PL/SQLLCO구조

PL/SQL과 일반 SQLHeap Memory를 사용하는데 있어서도 차이점이 있다는 것을 금방 알 수 있을 것이다.

 

- Oracle의 놀라운 메커니즘 Invalidation 자동화

Oracle의 장점 중 하나인 invalidation 자동화에 대해 잠시 설명을 해 보겠다. 이에 대한 내용이 자세히 언급된 곳은 많지 않았을 것이다. 우선 그림 7을 보면 SQL LCO의 구조에 대해 잘 보여주고 있다. Parent LCO와 두 개의 child LCO가 보일 것이다. 보통 이런 방식으로 저장되는 경우는 각각 다른 schema에 같은 이름의 table을 가지고 있을 때 동일한 SQLquery할 수 있을 것이다. 쉽게 예를 들면 scott1scott2란 두 user가 있는데 이들이 각각 emp라는 table을 가지고 있고 select * from emp;라는 동일한 query를 두 user가 전송했을 때 이러한 구조로 LCO가 생성되게 되는 것이다.

이때 child LCODependency Table에는 scott1의 경우 scott1.emp tableLCO를 참조하고 cott2의 경우 scott2.emp tableLCO를 참조하게 되는 것이다.

이 참조 과정에서 handlelock hold/wait list, pin hold/wait list를 이용하게 된다. 이때 중요한 것이 바로 lock이다. 참조하는 LCOlockshared mode로 잡아 사용하고 해제하는 것이 아니라 null mode로 유지하는 것이다. 이것이 바로 나중에 참조하는 table이 변경되었을 때 이 lock list를 없애 버림으로 인해 SQL Cursor(select * from emp;)를 따로 어떤 프로세스를 통해 invalidation한 상태로 만들지 않고 자동으로 invalidation하게 하는 것이다.

 

- Library cache에서 발생하는 Wait Event 소개

그럼 이제는 library cache에서 발생하는 주요 Wait Event들에 대해 알아보자. library cache에서 일어나는 자주 발생하는 Wait Event에는 3가지가 있다. 그것은 latch:library cache, library cache lock event, library cache pin event이다. 이것은 명칭에서도 알 수 있듯이 latch, lock, pin을 소유하기 위해 대기하는 event 이다. 이 동기화 자원들에 대하여 자세히 알아보자.

 

- Library Cache Latch

 우선 library cache latch에 대해 알아보면 이 latchlibrary cache 영역을 탐색하고 관리하는 모든 작업을 보호하는 데에 그 목적이 있다. Latch의 수는 일반적으로 shared pool latch의 수 보다는 많다. 왜냐하면 CPU개수보다 큰 소수 중 가장 작은 소수로 설정되어 있기 때문이다. 이 때문에 library cache latch를 획득하려는 프로세스가 CPU개수 보다 적다면 library cache latch 자원은 손쉽게 획득하는 대신에 shared pool latch를 가지고 경합할 확률이 높을 것이고 library cache latch의 개수보다 많은 프로세스가 획득하려 한다면 library cache latch를 가지고 경합을 하느라 shared pool latch의 경합은 상대적으로 줄어들 수 있다. 그렇다면 이러한 library cache latch 경합을 가중시키는 작업엔 어떤 것이 있을까? 바로 hard parsing이나 soft parsing이 과다한 경우와 자식 LCO가 많아 anonymous list의 탐색시간이 증가하는 경우이다. 그리고 SGA영역이 page out되는 극히 드문 경우를 예로 들어 볼 수 있다. 이에 대한 해결 책으로 PL/SQL block 내에서 자주 실행되는 SQL에 대해서는 Static SQL을 사용하면 된다.(Dynamic SQL은 안됨) LCOpin하여 soft parsing 없이도 cursor를 계속 재사용 할 수 있는 효과를 볼 수 있다.

그리고 SESSION_CACHED_CURSORS Parameter를 이용하여 3회 이상 수행된 SQL에 대해서는 PGA영역에 cursor의 주소 값과 SQL text를 저장하여 cursor 탐색 시 성능향상을 기대할 수 있다.(library cache latch도 획득해야 하고 soft parsing도 발생하지만 library 탐색시간이 매우 짧기 때문에 성능향상이 된다.) 하지만 application에서 SQL 수행 시 마다 log on/off하는 경우 이 parameter는 세션이 끊어지면 소용이 없기 때문에 성능 향상을 기대하기 어렵다. 때문에 connection pool을 함께 이용하는 것이 현명한 방법이다. 그리고 마지막으로 SGA영역의 page out의 경우는 잘 발생하지 않지만 만약을 대비해서 LOCK_SGA값을 TRUE로 하여 고정시켜 놓는 것이 좋다.

 

- Library Cache Lock

 Library cache lock(관련 뷰 : X$KGLLK, 10g-DBA_DDL_LOCKS, DBA_KGLLOCK)에 대해 설명하면 이것은 handle에 대해 획득하는 lock이라 볼 수 있다. 이것의 목적은 동일 object의 접근 및 수정에 대해 다른 client들로부터 예방하는 것이다. Lock은 세가지 모드를 갖게 되는데 shared, exclusive, null mode가 있다. Shared로 획득하는 경우는 parsing과 실행단계이고 exclusiveprocedure 생성이나 변경의 경우, recompile시와 table 변경의 경우가 있다. 보통 참조하는 LCO에 대해 exclusive모드와 shared모드로 각각 획득하려는 경합으로 인해 waiting이 발생하게 된다. null mode는 보통 실행 후에 참조하는 객체에 대해 null modelock을 소유하게 된다. 

 

- Library Cache Pin

 마지막으로 library cache pin(관련 뷰 : X$KGLPN, 10g-DBA_KGLLOCK)에 대해 설명하면 Heap datapin을 꽂아 변경되지 않도록 보장하는데 그 목적이 있다. 이것은 반드시 library cache lock을 획득한 후에 획득해야 한다. 이것은 sharedexclusivemode가 지원되며 이렇게 획득하는 경우를 살펴보면, shared mode로 획득하는 경우는 Heap Data를 읽을 때 pin을 걸어 object들의 변경을 예방하며 exclusive mode로 획득하는 경우는 Heap Data를 수정할 때이다. Heap data를 수정하는 경우는 procedure recompile이나 hard parsing 발생 시 execution plan을 세우는 과정에서 참조하는 LCO가 변경되면 안되기 때문에 pin을 걸어 보호한다.

 이때 발생하는 library cache lock이나 library cache pinV$SESSION_WAITP1, P2, P3 columnX$KGLOB View를 이용하여 object 정보를 구할 수 있다. P1=handle address, P2=lock address, P3=mode*100+namespace (lock mode : 1=null, 2=shared, 3=exclusive)이기 때문에 V$SESSION_WAIT을 조회하여 P1값을 구한 후 P1X$KGLOBkglhdadr column과 비교하여 kglnaobj columnquery해서 object의 이름을 구할 수 있다.

 

- 맺음말

위의 library caches에 관한 내용들을 종합적으로 정리해서 결론을 내려보면 Wait Event를 통해 그 Event가 왜 발생하였는가를 인지할 수 있다면 정확한 진단 역시 가능함을 알 수 있다. 그리고 덧붙여 내부적인 Event의 발생과정을 아는 것이 튜닝을 하게 될 때 넓은 시야를 가질 수 있도록 도와주고 좀더 효율적이고 정확한 튜닝을 할 수 있는 계기가 되리라 확신한다.

 

참고자료

OWI를 활용한 오라클 진단 & 튜닝 / ㈜엑셈 역

Advanced Oracle Wait Interface in 10g / 저자 조동욱 / ㈜엑셈

Oracle 8i Internal Services for Waits, Latches, Locks, and Memory / Steve Adams / O’Reilly

Manual

Oracle Database Concepts 10g R2

Oracle Database Reference 10g R2

Oracle Database Performance Tuning Guide 10g R2
반응형
Posted by [PineTree]
ORACLE/ADMIN2011. 11. 22. 23:54
반응형
oracle shared pool size얼마나 남았나?
 
select to_number(v$parameter.value) value, v$sgastat.bytes,
(v$sgastat.bytes/v$parameter.value)*100 "Percent Free"
from v$sgastat, v$parameter
where v$sgastat.name = 'free memory'
and v$parameter.name = 'shared_pool_size';

=============================================================
DB shared pool flush시키는 명령어
alter system flush shared_pool;

반응형
Posted by [PineTree]
ORACLE/OWI2009. 6. 30. 19:59
반응형

아직도 Shared pool 설정에 어려움을 느끼십니까?

 

작성자 : 한민호(blubeard@nate.com)

 

필자가 Oracle Internal에 관심을 가지게 된 것은 얼마 되지 않지만 공부를 하면서 이렇게 자료를 만들어 정리를 해보는 것도 좋은 경험이 되고 여러 사람들과 지식을 공유하고 싶었기 때문에 OKM에 기고하게 되었다.

SGA에 서 shared pool만큼 사이즈를 설정하기 어려운 Parameter가 없다. 그리고 이 shared pool의 크기는 너무 커도, 너무 작아도 문제가 된다., 얼마나 적절히 설정하느냐에 따라 DB의 성능을 좌우하게 된다. Parameter만 잘 설정해도 성능이 좋아진다니 이렇게 편하고 좋은 튜닝 방법이 어디 있을까 하는 생각도 든다. 하지만 shared pool의 크기를 아무 지식과 진단 없이 적절히 설정하기란 여간 까다로운 일이 아닐 수 없다. 특히 Row cacheLibrary cache는 크기를 각각 설정하는 것이 불가능하기 때문에 초보자에겐 이런 것들이 어려움으로 다가올 수 있다. Shared pool을 자세히 알아 봄으로써 그러한 걱정들을 이번 기회에 덜 수 있다면 훌륭한 DBA가 되는데 도움이 되리라 생각된다. 이에 Shared Pool을 설정함에 있어 진단의 지표로 OWI를 사용할 것이다.

 

- Wait Event의 중요성

 Programming을 해본 사람이라면 동기화 문제에 대해 매우 잘 알고 있을 것이다. Oracle역시 수많은 Transaction에 의해 작업이 되기 때문에 이 때 발생하는 동기화 문제들을 해결하기 위해 수 많은 Latch, Lock, Pin을 사용하고 있다. 이 동기화란 것은 Serial한 작업이기 때문에 성능에 막대한 영향을 주게 된다. Wait Event는 이러한 동기화 작업에 있어서 Critical Section에 들어가지고 못하고 대기하는 작업들의 대기시간 동안 발생하는 이벤트이다. 이 때문에 Wait Event 발생을 줄이는 것은 중요한 일이고 이를 잘 분석하여 Tuning하는 것은 매우 효과적인 방법인 것이다. 그럼 이제 Shared PoolWait Event의 관점에서 진단하고 분석해보기로 하겠다.

 

- Shared pool의 목적

Shared pool에 대해 간략히 설명을 해보자면 shared pool의 목적은 실행된 Cursor를 공유하여 CPUmemory를 효율적으로 사용하는 데 있다. CursorSQL의 경우 실행할 때 필요한 실행계획 같은 실행 정보를 담고 있는 SGA상에 할당된 Heap Memory를 말한다. 물론 공유 할 수 있는 것들은 다양하다. 공유할 수 있는 정보들을 나열하자면 SQL구 문, 실행계획, PL/SQL소스와 그것들의 실행정보, table, view 같은 object 등이 있다. 이것들을 공유한다면 동일한 PL/SQL이 나 SQL을 실행함에 있어 매번 실행계획을 만들며 hard parsing이 일어나는 부하를 예방할 수 있다.

 

- Shared pool의 구성요소

shared pool을 구성하고 있는 구성요소에 대해 알아보겠다. 우선 shared pool의 구성요소는 4가지로 나뉜다. Process목록, Session목 록, Enqueue목록, Transaction목 록 등이 할당된 Permanent AreaSQL문 을 수행하는데 필요한 모든 객체 정보를 관리하는 Library cache, dictionary 정보를 관리하는 Row Cache, 그리고 마지막으로 동적 메모리 할당을 위한 공간인 Reserved Area로 나눌 수 있다.

 

- Heap Manager를 통한 메모리 관리

메모리에 대한 할당 및 해제 작업은 Heap Manager를 통해 동적으로 관리가 된다.Heap Manager에 대해 간략히 알아보면 Top-levelHeap과 그 하위에 여러 개의 Sub-Heap을 포함하는 구조를 이루고 있다.Heap은 또한 linked list구 조의 Extent들로 구성이 되어 있으며 Extent는 여러 개의 chunk로 구성되어있다. 실제적으로 chunk의 사용 현황에 대해 알고 싶다면 X$KSMSP라는 View를 통해 관찰 할 수 있을 것이다.

 

- Chunk의 관리

Chunk4가지 상태로 관리가 된다.4가지 상태는 Free, Recreatable, Freeable, Permanent. 이러한 chunk들의 상태에 따라 linked list가 구성되는 것이다. 상태의 이름만으로도 그것이 어떤 상태인지 알 수 있을 것이다. 더 정확히 설명 하자면 Free는 즉시 사용 가능한 상태를 말한다.Free 상태의 chunk들로 묶여 있는 linked listfree list인 것이다. 구체적으로 설명하면 이것은 255개의 bucket이 있고 각 bucketfree chunk들 이 linked list구조로 연결되어있다. 이때 bucket은 각각의 정해진 기준의 크기 이하의 chunk들로만 구성되어 있다. 이러한 이유로 bucket이 아래로 갈수록 chunk들의 크기가 크다. Recreatable은 재생성 가능한 상태이다. 뒤에서 다시 설명하겠지만 이것은 unpinned(현 재 사용되고 있지 않은)일 때 재사용이 가능하다. 쉽게 말하자면 이것은 사용이 되었었지만 다시 사용될 확률이 낮아져서 재사용이 가능한 상태가 된 것이며, 현재 사용 중이 아니라면 chunk를 재사용할 수 있도록 이러한 상태의 chunk를 묶어 LRU list로 관리한다. (관련 뷰 : X$KGHLU) 그리고 Freeablesession이나 call 동안에만 필요한 객체를 저장하고 있는 상태이며 이는 session등이 금방 끊길 수도 있기 때문에 chunk가 필요할 때 할당의 대상이 되지는 못한다. Permanent는 말 그대로 영구적인 객체를 저장하고 있는 상태이며 이것 역시 사용할 수 없는 chunk.

실제 Heap Dump를 이용하면 R이 앞에 붙어서 상태가 정의 되어 있는 것을 볼 수 있는데 이것은 SHARED_POOL_RESERVED_SIZEParameter를 통해 발생한 chunk들이다.chunk도 적절히 사용하면 매우 중요한 튜닝 요소가 될 수 있다. 이것에 대해 oracle 매뉴얼에서는 PL/SQL block이 많이 사용되는 경우를 예로 들고 있다., 이것은 large chunk를 위해 할당된 공간인 것이다. Parameter를 정해 주지 않는다면 설정된 shared_pool_size5%default value로 분류된다. Steve AdamsOracle Internal이나 매뉴얼에서도 5000byte 이상의 큰 object를 위한 공간이라고 설명한다. 이는 large chunk가 요구되지 않는다면 굳이 설정할 필요가 없다는 말도 되는 것이다. 이러한 튜닝 요소에 초점을 맞추어 설정하면 되는 parameter인 것이다. 이것들 역시 linked list로 관리되며 명칭은 Reserved Free list라고 부른다.

(아 래 그림 1을 참조한다면 이해하는 데에 도움이 될 것이다.)


[그림 1] Shared Pool Heap 구조(출처 : Advanced OWI in Oracle 10g / ㈜엑셈)

 

정리를 해보자면 chunk는 사용할 수 있는 것과 없는 것으로 나눌 수 있다. 그 중에 실제 chunk 할당 과정에서 latch경 합을 벌여 Wait Event가 발생하기 때문에 free listLRU list에서 관리되고 있는 chunk들에 주목을 할 필요가 있을 것이다. 왜냐하면 운영 시 peak time때의 할당된 chunk의 총 크기가 곧 shared poolsize를 적절히 결정하는 데에 중요한 역할을 하기 때문이다. 이것에 대한 설명은 Wait Event의 발생과 연관 지어 이야기 해 보겠다.


- Shared Pool
의 관리

Chunk를 할당하는 과정에서 반드시 필요한 것이 shared pool latch의 획득이다. 하지만 이러한 shared pool latch는 아쉽게도 shared pool당 단 1개 밖에 존재하지 않는다. 이것은 즉, chunk를 동시에 할당 받아야 할 상황이라면 이것을 획득하는 과정에서 경합을 벌이게 된다는 의미이다. 무엇 때문에 이렇게 shared pool latch 수를 적게 만들어 놓았는지 정확히 알 수는 없지만 여러 개를 만들어 놓았다면 역시나 동기화 문제를 관리하는데 있어 어려움이 있기 때문이 아닐까 싶다. 다행히도 Oracle 9i부터는 Hidden Parameter_KGHDSIDX_COUNT를 이용하여 하나의 shared Pool7개 까지의 Sub-Pool로 나누어 관리하는 것이 가능해졌다. 그리고 더 반가운 소식은 각각의 Sub-pool당 독자적인 free list, LRU list, shared pool latch를 가짐으로 인해 부족했던 자원에 대한 경합을 그나마 감소시킬 수 있게 되었다. 그러나 경합은 감소했을지 몰라도 CPU의 개수나 SHARED_POOL_SIZE가 충분히 크지 않다면 ORA-4031에러의 발생위험이 1개의 shared pool로 관리됐을 때보다 더 높다는 것이다. 그래서 권장하는 방법이 CPU 4개 에 SHARED_POOL_SIZE250m이 상일 때 Sub-pool을 사용하는 것이다. 한 때는 하나의 Sub-pool에 할당 가능한 chunk공 간이 없으면 다른 Sub-pool에 사용 가능한 free chunk가 있음에도 찾지 못했던 버그도 있었다. shared pool latch에 대해 좀 더 알아보자면 실제적으로 shared pool latch를 소유하는 시간이 shared pool latch를 대기하게 하는 중요한 이유이다. 때문에 latch를 획득한 후에 일어나는 작업들을 알면 경합의 포인트를 알 수 있을 것이다.

 

 - Chunk의 할당과정

Shared pool latch를 획득하게 되면 우선 free chunk를 찾기 위해 free list를 탐색한다. 그리고 적절한 free chunk가 있다면 할당을 받지만 없다면 LRU list를 탐색하게 된다. 이것마저도 찾지 못한다면 Reserved Free List를 탐색하고 이것 역시 실패하면 Spare Free Memory를 탐색하게 된다. 이 모든 과정이 실패가 되었을 때 ORA-4031에러가 발생하게 되는 것이다. 이 과정에서 할당을 받게 된다면 딱 필요한 크기만 할당을 받고(split) 나머지는 다시 free list에 등록이 되기 때문에 free list가 할당이 된다고 해서 반드시 짧아지는 것은 아니다. 그리고 적절한 chunk를 찾기 위해 위에서와 같이 여러 과정은 거치지만 이 과정은 생각보다 매우 빠른 시간 안에 이루어진다. 하지만 이것들이 다수의 작업이 된다면 경합에 대한 wait time은 피부로 느껴질 것이다. 여기서 이제껏 언급이 없었던 Spare Free Memory에 대해 궁금해하는 분이 많을 꺼 같아 간단하게 설명하자면(이 내용은 Steve AdamsOracle Internal에 내용이 있다) instancestart up 되었을 때 shared pool size에 정해진 크기의 절반만이 shared pool에 할당된다. 이것은 성능을 극대화 하는데 에도 연관이 있으리란 생각이 든다. Chunk의 수가 줄면 그 만큼 free list가 짧아지기 때문에 그에 대한 탐색시간도 짧아지고 shared pool latch의 소유 시간 역시 짧아지기 때문에 메모리를 숨겨놓지 않았을까 생각된다. 위의 과정들을 미루어 짐작해볼 때 shared pool latch의 소유시간은 free list의 길이와 얼마나 빨리 적절한 chunk를 찾느냐에 따라서 결정된 다는 것을 알 수 있을 것이다. 그럼 free list의 길이가 길어지는 것은 어떠한 경우 일까? 바로 그것은 chunk split가 다량으로 발생하여 단편화(fragmentation) 되었을 때이다. 이러한 경우 free list의 길이가 길어지게 되는 것이다. 단편화는 hard parsing에서 일어나는 것인데 hard parsing에 대해 모르는 독자들을 위하여 간단히 설명하면 처음 실행하는 SQL문이 있다면 이것에 대한 실행정보를 저장하고 있는 Heap Memory 할당이 필요한데 이 Heap이 바로 chunk인 것이다. 이러한 실행계획을 만들고 chunk에 할당하는 과정은 매우 부하가 있기 때문에 hard parsing이라고 이름 붙여진 것이다. 이런 과도한 단편화로 인해 shared pool latch의 경합만 가중 시키는 것이 아니다.chunk 할당이 요구되는 hard parsing이 이루어 질 때 적절한 free chunk를 찾지 못하여 ORA-4031에 러를 유발하게 된다.

 

- Shared Pool Size 설정

지금까지 설명했던 것들을 가지고 shared pool size에 대해 결론을 내 보면, 첫째로, memory가 무조건 크다는 생각으로 shared pool을 늘리면 안 된다고 볼 수 있다. 이것은 오히려 free list의 길이만 늘어나게 되기 때문이다. 그리고 V$SGASTAT를 통해 확인한 shared poolfree memory가 작다고 해서 SHARED_POOL_SIZE를 늘려서는 안 된다. Free memory는 단지 free chunk의 합이기 때문이다. 이는 즉 LRU list, reserved list, spare memory도 있기 때문에 크게 문제가 되는 것은 아니라는 말이다. 지금까지 설명한 것을 고려해 본다면 적절한 크기를 정하는 데는 매우 도움이 될 것이다. 만약 초보 DBA라면 Oracle에 서 제공하는 advice를 이용하는 것도 괜찮은 방법일 듯싶다. OEM구성을 하여 Enterprise Manager를 보면 memory tab에서 shared pool 부분의 advice버튼만 클릭하면 적절한 shared pool 크기에 대한 지침을 제공하고 있다.(그 림 2를 참조하시오) 이것이 아주 정확한 척도가 되지는 못할지라도 초보 DBA에게는 매우 매력 있는 기능임에는 틀림이 없다. 이 지침은 되도록이면 peak time 이후에 이용하는 것을 권장한다.

[그림 2] Enterprise ManagerShared pool advice

 

Shared Pool Size를 적절히 줄이게 되면 free list 탐색시간의 감소로 인해 hard parsing에 의한shared pool latch의 경합을 줄이는 효과를 볼 수 있지만 ORA-4031에 러의 위험이나 상주할 수 있는 공유 객체의 수가 줄어들어 LRU list를 자주 이용하기 때문에 오히려 부가적인 hard parsing을 발생시킬 수 있음에 유의해야 한다. 이때 오르내리는 객체가 프로시저나 패키지라면 그 부하는 상당할 것이다. 이에 대비하여 DBMS_SHARED_POOL.KEEP을 이용하여 메모리에 고정시키는 방법도 매우 유용하다. Shared poolflush해도 내려가지 않기 때문이다. Shared pool latch가 발생하는 것을 가장 줄일 수 있는 방법은 bind변 수의 사용이나 CURSOR_SHARING Parameter를 설정하는 것이다. CURSOR_SHARING parameterSQL문 장을 자동으로 bind변수치환을 해주는 변수이다. 위에서 언급했던 Flush Shared pool에 대하여 잠시 설명을 하고 가면 alter system flush shared_pool;이란 명령을 통해 shared poolflush 시킬 수 있다. 이 작업은 단편화된 free chunk에 대해 coalesce 작업이 이루어 지기 때문에 유용하지만 NOCACHE 옵션이 없는 sequence가 있다면 예상치 못한 gap이 생길 수도 있기 때문에 유의해야 한다.

 

 - Library Cache LatchShared Pool Latch의 관계

Shared pool을 튜닝 하는데 있어 반드시 shared pool latch 획득만이 문제가 되는 것은 아니다.  바로 shared pool latch 획득 이전에 library cache latch의 획득이 먼저 있기 때문이다. 이것을 비롯한 parsing에 대해 좀더 이해를 돕기 위해 아래의 그림 3을 참조하기 바란다.

작업

Hard Parsing

Soft Parsing

Syntax, Semantic, 권한체크

Library cache latch 획득

Library cache 탐색

LCO가 있다면 Library cache latch 해제

 

Shared Pool latch 획득

 

할당 가능한 Chunk탐색 및 Chunk할당

 

Shared Pool latch 해제

 

Parse Tree Execution Plan 생성

 

[그림 3]  parsingshared pool latchlibrary cache latch

 그림 3를 보면 알 수 있듯이 hard parsingsoft parsing 보단 부하가 큰 작업 임을 알 수 있다. 또한 library cache latchshared pool latch 획득 시점을 미루어 보아 동시에 많은 세션이 library cache latch를 획득하려고 하게 되면 이것에 대한 병목 현상으로 shared pool latch에 대한 경합은 상대적으로 줄어들 수 있을 것이란 예상도 가능하다. 그렇다면 이렇게 shared pool latch에 영향을 주는 library cache latch에 대해서도 자세히 알아볼 것이다.

 

- Library Cache의 구조와 관리

Library cache에 할당 받는 Heap memoryshared pool latch를 걸고 할당 받은 free chunk이다. 이때 Library Cache Manager(KGL)에 의해 관리되는데 이는 내부적으로 Heap Manager(KGH)를 이용하는 것이다. 이때 할당된 free chunkLCO(Library Cache Object)handle을 저장하는데 사용된다. Library Cache Memory는 크게 hash function, bucket, handle list, LCO로 구성되어 있다. 하나씩 설명을 해보면 hash functionbucket을 결정하기 위한 연산을 수행하는 함수로 보면 된다. 객체에 따라 SQL의 경우 SQL TEXT를 그대로 numeric 값으로 변환하여 bucket을 결정하고 SQL외의 객체들은 schema, object name, DB linknumeric 값으로 변환하여 bucket을 결정한다. Bucket의 성장은 LCO의 크기가 매우 많아져서 성장이 불가피할 때 성장하게 되는데 이때 대략 2배 크기의 소수로 확장하게 된다. 그리고 bucket의 초기 값은 _KGL_BUCKET_COUNT로 설정이 가능하다.

아래 그림 4, 5는 필자가 그린 handleLCO의 구조, 그리고 그것에 대한 간략한 설명이다.


 

[그림 4] Handle의 구조


[그림 5] LCO의 구조

[그림 6] Library cache 구조 (출처 : Advanced OWI in Oracle 10g / ㈜엑셈)

 

위의 그림 4, 5를 숙지하였다면 handle이 무엇이고 LCO가 무엇인지, 또 이것이 저장하는 정보에 대하여 알 수 있었을 것이라고 예상 된다. 이제 그림 6을 보면 대략적인 구조가 머리 속에 들어 올 것이다. 여기서 특징적인 것은 SQL의 경우 child table을 갖는 다는 점이고 그 child table이 저장하고 있는 실제적 자식 handleLCO는 익명 리스트로 관리되고 있다는 점이다. 물론 PL/SQL의 경우는 조금 다르다. 이것의 구조는 그림 7,8을 보면 좀더 명확히 알 수 있다.


[그림 7] SQLLCO구조


[그림 8] PL/SQLLCO구조

PL/SQL과 일반 SQLHeap Memory를 사용하는데 있어서도 차이점이 있다는 것을 금방 알 수 있을 것이다.

 

- Oracle의 놀라운 메커니즘 Invalidation 자동화

Oracle의 장점 중 하나인 invalidation 자동화에 대해 잠시 설명을 해 보겠다. 이에 대한 내용이 자세히 언급된 곳은 많지 않았을 것이다. 우선 그림 7을 보면 SQL LCO의 구조에 대해 잘 보여주고 있다. Parent LCO와 두 개의 child LCO가 보일 것이다. 보통 이런 방식으로 저장되는 경우는 각각 다른 schema에 같은 이름의 table을 가지고 있을 때 동일한 SQLquery할 수 있을 것이다. 쉽게 예를 들면 scott1scott2란 두 user가 있는데 이들이 각각 emp라 는 table을 가지고 있고 select * from emp;라는 동일한 query를 두 user가 전송했을 때 이러한 구조로 LCO가 생성되게 되는 것이다.

이때 child LCODependency Table에 는 scott1의 경우 scott1.emp tableLCO를 참조하고 cott2의 경우 scott2.emp tableLCO를 참조하게 되는 것이다.

이 참조 과정에서 handlelock hold/wait list, pin hold/wait list를 이용하게 된다. 이때 중요한 것이 바로 lock이다. 참조하는 LCOlockshared mode로 잡아 사용하고 해제하는 것이 아니라 null mode로 유지하는 것이다. 이것이 바로 나중에 참조하는 table이 변경되었을 때 이 lock list를 없애 버림으로 인해 SQL Cursor(select * from emp;)를 따로 어떤 프로세스를 통해 invalidation한 상태로 만들지 않고 자동으로 invalidation하게 하는 것이다.

 

- Library cache에서 발생하는 Wait Event 소개

그럼 이제는 library cache에서 발생하는 주요 Wait Event들에 대해 알아보자. library cache에서 일어나는 자주 발생하는 Wait Event에는 3가지가 있다. 그것은 latch:library cache, library cache lock event, library cache pin event이다. 이것은 명칭에서도 알 수 있듯이 latch, lock, pin을 소유하기 위해 대기하는 event 이다. 이 동기화 자원들에 대하여 자세히 알아보자.

 

- Library Cache Latch

 우선 library cache latch에 대해 알아보면 이 latchlibrary cache 영역을 탐색하고 관리하는 모든 작업을 보호하는 데에 그 목적이 있다. Latch의 수는 일반적으로 shared pool latch의 수 보다는 많다. 왜냐하면 CPU개수보다 큰 소수 중 가장 작은 소수로 설정되어 있기 때문이다. 이 때문에 library cache latch를 획득하려는 프로세스가 CPU개수 보다 적다면 library cache latch 자원은 손쉽게 획득하는 대신에 shared pool latch를 가지고 경합할 확률이 높을 것이고 library cache latch의 개수보다 많은 프로세스가 획득하려 한다면 library cache latch를 가지고 경합을 하느라 shared pool latch의 경합은 상대적으로 줄어들 수 있다. 그렇다면 이러한 library cache latch 경합을 가중시키는 작업엔 어떤 것이 있을까? 바로 hard parsing이 나 soft parsing이 과다한 경우와 자식 LCO가 많아 anonymous list의 탐색시간이 증가하는 경우이다. 그리고 SGA영역이 page out되는 극히 드문 경우를 예로 들어 볼 수 있다. 이에 대한 해결 책으로 PL/SQL block 내에서 자주 실행되는 SQL에 대해서는 Static SQL을 사용하면 된다.(Dynamic SQL은 안됨) LCOpin하여 soft parsing 없이도 cursor를 계속 재사용 할 수 있는 효과를 볼 수 있다.

그리고 SESSION_CACHED_CURSORS Parameter를 이용하여 3회 이상 수행된 SQL에 대해서는 PGA영역에 cursor의 주소 값과 SQL text를 저장하여 cursor 탐색 시 성능향상을 기대할 수 있다.(library cache latch도 획득해야 하고 soft parsing도 발생하지만 library 탐색시간이 매우 짧기 때문에 성능향상이 된다.) 하지만 application에 서 SQL 수행 시 마다 log on/off하 는 경우 이 parameter는 세션이 끊어지면 소용이 없기 때문에 성능 향상을 기대하기 어렵다. 때문에 connection pool을 함께 이용하는 것이 현명한 방법이다. 그리고 마지막으로 SGA영역의 page out의 경우는 잘 발생하지 않지만 만약을 대비해서 LOCK_SGA값을 TRUE로 하여 고정시켜 놓는 것이 좋다.

 

- Library Cache Lock

 Library cache lock(관련 뷰 : X$KGLLK, 10g-DBA_DDL_LOCKS, DBA_KGLLOCK)에 대해 설명하면 이것은 handle에 대해 획득하는 lock이라 볼 수 있다. 이것의 목적은 동일 object의 접근 및 수정에 대해 다른 client들로부터 예방하는 것이다. Lock은 세가지 모드를 갖게 되는데 shared, exclusive, null mode가 있다. Shared로 획득하는 경우는 parsing과 실행단계이고 exclusiveprocedure 생성이나 변경의 경우, recompile시와 table 변경의 경우가 있다. 보통 참조하는 LCO에 대해 exclusive모드와 shared모 드로 각각 획득하려는 경합으로 인해 waiting이 발생하게 된다. null mode는 보통 실행 후에 참조하는 객체에 대해 null modelock을 소유하게 된다. 

 

- Library Cache Pin

 마지 막으로 library cache pin(관련 뷰 : X$KGLPN, 10g-DBA_KGLLOCK)에 대해 설명하면 Heap datapin을 꽂아 변경되지 않도록 보장하는데 그 목적이 있다. 이것은 반드시 library cache lock을 획득한 후에 획득해야 한다. 이것은 sharedexclusivemode가 지원되며 이렇게 획득하는 경우를 살펴보면, shared mode로 획득하는 경우는 Heap Data를 읽을 때 pin을 걸어 object들의 변경을 예방하며 exclusive mode로 획득하는 경우는 Heap Data를 수정할 때이다. Heap data를 수정하는 경우는 procedure recompile이 나 hard parsing 발생 시 execution plan을 세우는 과정에서 참조하는 LCO가 변경되면 안되기 때문에 pin을 걸어 보호한다.

 이때 발생하는 library cache lock이나 library cache pinV$SESSION_WAITP1, P2, P3 columnX$KGLOB View를 이용하여 object 정보를 구할 수 있다. P1=handle address, P2=lock address, P3=mode*100+namespace (lock mode : 1=null, 2=shared, 3=exclusive)이기 때문에 V$SESSION_WAIT을 조회하여 P1값을 구한 후 P1X$KGLOBkglhdadr column과 비교하여 kglnaobj columnquery해 서 object의 이름을 구할 수 있다.

 

- 맺음말

위의 library caches에 관한 내용들을 종합적으로 정리해서 결론을 내려보면 Wait Event를 통해 그 Event가 왜 발생하였는가를 인지할 수 있다면 정확한 진단 역시 가능함을 알 수 있다. 그리고 덧붙여 내부적인 Event의 발생과정을 아는 것이 튜닝을 하게 될 때 넓은 시야를 가질 수 있도록 도와주고 좀더 효율적이고 정확한 튜닝을 할 수 있는 계기가 되리라 확신한다.

 

참고자료

OWI를 활용한 오라클 진단 & 튜닝 / ㈜엑셈 역

Advanced Oracle Wait Interface in 10g / 저자 조동욱 / ㈜엑셈

Oracle 8i Internal Services for Waits, Latches, Locks, and Memory / Steve Adams / O’Reilly

Manual

Oracle Database Concepts 10g R2

Oracle Database Reference 10g R2

Oracle Database Performance Tuning Guide 10g R2

반응형

'ORACLE > OWI' 카테고리의 다른 글

shared pool의 heap구조 dump자료  (0) 2013.06.23
Oracle Wait Event 모니터링  (0) 2009.12.02
Latch의 발생과 경합의 원인  (0) 2009.03.09
Oracle에서 Latch 가 성능 저하의 원인이 아닙니다  (0) 2009.03.01
Enqueue 와 Latch  (0) 2009.03.01
Posted by [PineTree]