[4) 라이브러리 캐시 최적화 원리] 3. 라이브러리 캐시 구조

Yu River·2022년 7월 7일
0

[1] SGA(System Global Area)

  • 디스크에서 읽어온 데이터를 저장하는 메모리 영역이다.
  • 저장된 데이터를 읽거나 변경하는 작업에서 사용되는 공용 메모리 영역이다.
  • 메모리 사용을 최소화하면서 처리성능을 최대화하기 위해 SGA를 사용하는 것이다.

(1) SGA 구성

  • Database buffer cache
  • Streams Pool
  • Java Pool
  • Large Pool
  • Redo Log Buffer
  • Shared Pool

Shared Pool

  • SQL, PL/SQL 수행에 필요한 정보를 저장한다.
  • 한번 처리된 SQL의 실행 정보를 공하여 자원의 사용을 최소화하고 SQL 수행속도 증가시키기 위해 사용한다.
  • Shared Pool은 Variable 영역과 Permanent 영역으로 나누어진다.
    • Variable 영역
      • Shared Pool
      • Java Pool
      • Large Pool
      • Streams Pool
    • Permanent Area(시스템 영역, 고정영역)
      • SGA 관리 메커니즘이 있다.
      • 오라클 파라미터 정보를 저장한다.
      • 자동 할당되며 사용자가 지정할 수 없다.
      • SGA구성 요소 중 Fixed Size(고정 사이즈)에 해당한다.
  • ⭐️ Shared Pool에 Library Cache가 위치하며 Library Cache는 PL/SQL, SQL에 대한 분석 정보(Parse Tree)실행계획을 저장한다.
  • ⭐️ Shared Pool에 Dictionary Cache가 위치하며 테이블, 인덱스, 뷰, 함수 및 트리거 등의 사용자, 구조, 권한 등의 dictionary data 정보를 저장한다.
  • ⭐️ Shared Pool에 위치한 Dictionary Cache는 참조 데이터를 row 단위로 가지며 Row Cache 라고도 불린다.
  • Shared Pool에 Reserved Area(예약 영역)이 위치한다.
    • 크기가 큰 객체를 저장하는 영역이다.
    • 동적 메모리 할당 시에 메모리 조각 부족으로 인한 SQL실행 실패(ORA-4031)를 방지하기 위한 공간이다.
  • Shared Pool에 Spare Free Memory이 위치한다.
    • 단편화 최소화를 위해 일정 크기를 고정 영역에 숨겨둔다.
    • 메모리 할당이 꼭 필요한 경우 이 영역에서 할당 받는다.

[2] 라이브러리 캐시 구성

(1) 라이브러리 캐시 특징

  • SQL문 수행과 관련된 모든 정보를 저장한다.
  • 저장된 정보를 빠르게 찾고 저장하기 위해 사용한다.
  • Database Buffer Cache와 같이 LRU 알고리즘을 사용하여 관리한다.

    ✅ shared pool latch

    • shared pool에서 특정 object 정보 혹은 SQL 커서를 위한 free chunk 할당 받을 때 필요하다.
    • 동시 사용자가 순간적으로 과도한 "하드파싱" 부하를 일으킨다면 shared pool latch에 대한 경합 현상이 발생할 수 있다.
    • 9i 이전 : 하나의 shared pool latch로 전체 관리하였다.
    • 9i 이후 : shared pool을 여러 개의 sub pool로 나누어 관리할 수 있게되면서 latch도 7개까지 사용이 가능하게 되었다.

(2) Library Cache Object(LCO)

  • 라이브러리 캐시에 저장되는 정보의 단위이다.

1. 캐싱 정보 분류_1

  • Library Cache 안에서 공유되는 부분
    • SQL 텍스트
    • Execution Plan
    • Bind Variable Data Type과 Length 등
  • 실행 가능한 LCO
    • Package
    • Procedure
    • Function
    • Trigger
    • Anonymous PL/SQL Block
  • Object LCO : object 정보
    • Shared Cursor(공유 커서)
    • Table Definition(테이블 정의)
    • View Definition(뷰 정의)
    • Form Definition

      ✅ schema object information

      • 저장 포맷이 다르지만 data dictionary cache에도 저장된다.

2. 캐싱 정보 분류_2

  • Stored Object
    • 생성 후 drop 하기 전까지 데이터베이스에 영구적으로 보관되는 object이다.
    • 생성될 때부터 이름을 가진다.
    • 테이블, 인덱스, 클러스터, 뷰, 트리거, 패키지, 사용자 정의함수, 프로시저 등이 있다.
  • Transient Object
    • 실행시점에 생성돼서 인스턴스가 떠있는 동안에만 존재하는 일시적인 object 별도로 이름을 지정하지 않는다.
    • 문장을 구성하는 전체 문자열 그대로가 이름 역할을 한다.
    • 커서, anonymous PL/SQL 등이 있다.

(3) 작동 방법

  • Heap Manager와 Library Cache Manager가 관리한다.

1. Library Cache Manager

  • Hashing 기법을 이용하여 Object에 대한 이름을 갖는 Handle을 찾는데, 이 Handle은 다시 해당 Object를 가리킨다.

    ✅ Handle(= Library cache Handel)

    • Library cache object(LCO)를 관리한다.
    • 실제 정보가 있는 LCO에 대한 메타정보 및 위치값을 저장한다.
    • SQL은 SQL 텍스트를 상수로 변환해서 bucket이 되며 "Child LCO"가 존재한다.
    • SQL 이외 정보들(table, view etc)은 "user + object name + DB link"를 상수로 변환해서 bucket이 되며 "Child LCO"가 없다.
  • Library Cache Manager가 object 찾는 순서
    1. 필요한 Object의 Namespace, Object Name, Owner, Database Link 값에 "Hash Function" 적용
    2. 해당 Object가 존재하는 Hash Bucket 찾기 (SQL 문장의 경우 앞뒤 64바이트의 글자 이용)
    3. Hash Bucket의 Linked List를 따라 원하는 Object의 실제 존재 유무 체크
      - Object 존재 : 찾은 Object를 사용
      - Object 존재하지 않음

      Object가 존재하지 않을 때

      1. Library Cache Manager는 주어진 이름으로 Empty Object 생성
      2. 생성된 Empty Object를 Hash Table에 포함시킨다.
      3. 오라클 프로세스에게 해당 Object를 로드하도록 요청한다.
      4. 오라클 프로세스가 해당 Object를 디스크에서 읽어, Heap Manager에 의해 새로이 할당된 메모리에 올려놓는다.
      5. 해당 Object를 사용한다.
  • Child LCO
    • SQL 커서 : 부모 LCO 밑에 schema 별로 자식 LCO를 소유한다.이 때 version count는 자식 LCO수를 의미한다.
    • table, procedure 등은 schema명과 함께 저장되므로 유일성이 보장되어 자식 LCO가 없다.

Library Cache Manager가 SQL 문 찾는 순서

  • 같은 문장을 찾지 못한 경우는 SQL 문은 다시 Parsing된다.(하드 파싱)
  • search Shared SQL Area -> search data dictionary
  1. Bucket 찾기
    • SQL 문에 Hash Function 적용 후 SQL 문의 Handle이 있는 Bucket을 찾아간다.
  2. 공유 가능한 SQL 문 찾기
    • 해당 Bucket 안에는 다른 SQL문이면서 Hash Function 값만이 같은 여러 SQL들이 있을 수 있으므로 이 Bucket List를 따라가면서 공유 가능한 같은 SQL이 있는지를 확인한다.

      ✅ Bucket List에서 같은 문장을 발견하였지만 서로 다른 Version 존재 가능성이 있는 경우

      SQL 문은 같지만 다음과 같은 경우는 서로 다른 버전으로 존재하며 공유되지 않는다.

      • 서로 다른 유저의 Object를 사용한 경우
      • 바인드 변수 데이터 타입이 다른 경우
      • 서로 다른 Application 정보를 사용하는 경우

(4) Shared Pool Latch & Library Cache Latch

1. Shared Pool Latch

  • Shared Pool 구조를 보호한다.
  • Shared pool의 힙 영역 탐색 및 free chunk를 할당,해지,재사용 작업 전에 이들을 보호하기 위해 획득한다.
  • Shared Pool에 하나의 Shared pool latch를 설정할 수 있으며 오라클 9i 이상부터는 Shared Pool을 여러 개의 서브풀로 최대 7개까지 나누어서 관리할 수 있다.
  • 하드 파싱이 빈번해지면 경합 발생률이 높아진다.
  • 큰 Shared Pool은 긴 Free lists를 유지하는 경향이 있어 free lists를 검색할 때 장시간 소요된다. 이 때 Shared pool latch 경합이 발생한다.
  • row chcahe 락과 row chache objects 래치는 Data dictionary cache 객체에 대한 동시 액세스를 제어한다.

2. Library Cache Latch

  • 라이브러리 캐시 체인을 탐색하고 변경할 때 획득한다.
  • 대기 이벤트에서 latch :: library cache 로 표기된다.
  • Library Cache Latch 개수가 CPU 개수에 근접하므로(적다는 소리ㅎ) 하드 파싱 및 소프트파싱이 많이 발생해도 이 latch에 대한 경합이 증가한다.
  • Library Chche 구조 내의 객체를 변경/탐색/pin/lock/적재/실행할 때마다 획득한다.
  • 라이브러리 캐시 영역에서 작업하고자 하는 모든 프로세스는 반드시 해당 해시 버킷을 보호하는 이 래치를 획득해야한다.
  • 경합 발생률이 높아 시스템 성능과 직접적인 관련이 있다.
  • 파싱 단계에서 대기 시간이 긴 이유는 대부분 라이브러리 캐시 래치 또는 shared pool 를 획득하는 과정에서 경합이 발생하기 때문이다.
  • 큰 version count(Child Cursor)를 가진 경우 익명 리스트가 길어져서 소프트 파싱 시에 검색 시간이 길어져 성능이 저하될 수 있다.
    • 해결법은 객체명을 유일하게 부여하는 것이다.

래치에 의한 경합 감소 방법

  • SQL 커서에 해당하는 LCO를 pin한다.
    • 메모리에 고정되기 때문에 라이브러리 캐시 래치를 획득하지 않고도 LCO 참조가 가능하다.
  • 한 세션 내에서 세 번 이상 수행된 SQL 커서들의 위치와 SQL문을 PGA에 저장한다.
    • 저장 SQL 커서 수는 SESSION_CACHED_CURSORS 파라미터에 의해 결정된다.
    • soft 파싱 수행과 라이브러리 캐시 래치를 획득해야 한다.
    • 라이브러리 캐시 메모리 구조를 탐색하지 않고 바로 LCO 위치로 찾아온다.
      • 라이브러리 캐시 래치 보유 시간을 단축하며 그 만큼 래치 경합이 감소된다.

(5) Library Cache Lock & Library Cache Pin

⭐️ 키워드 :: 하드파싱과 관련된 대기 이벤트

  • LCO를 보호하기 위해 사용된다.

순서

  1. handle Lock을 획득한다.
  2. LCO의 실제 내용이 담긴 heap에서 정보를 읽거나 변경 시 LCO를 읽고 쓰고, 실행하는 동안 다른 프로세스에 의해 정보가 변경되거나 캐시에서 밀려나는 것 방지하기 위해 Pin을 획득한다.

공통점

  • Shared Pool Latch & Library Cache Latch 경합은 소프트/하드 파싱을 동시에 심하게 일으킬 때 발생한다.
  • Library Cache Lock & Library Cache Pin 대기 이벤트
    • SQL 수행 도중 DDL 문 실행 시 발생한다.
    • 트랜잭션이 활발 할 때 DDL문을 실행하며 데이터베이스 object 정의를 변경하면 라이브러리 캐시에 심한 부하가 발생한다.
    • Parsing 과정에서 경합이 발생하면 각각 "latch: library cache"(soft), "latch: shared pool"(hard) 대기 이벤트를 발생한다.
    • Hard parsing : 새로운 커서를 생성해서 library cache chain 길이가 증가되어 검색 시간이 증가 되므로 성능이 저하된다.

Library Cache Lock

  • 라이브러리 캐시 객체에 접근/변경할 때 라이브러리 캐시 핸들에 대해 획득하는 락
  • 파싱 수행중 : shared 모드로 락을 획득
  • 파싱 종료
    • 널 모드로 변경한다.
    • 락을 널모드로 유지한 상태에서 LCO가 변경되면 널 모드 락을 소유한 SQL LCO들을 모두 찾아 자동으로 Invalidation(무효화) 시킨다.
    • SQL이 참조하는 모든 객체에 대해서도 동일한 모드로 획득한다.

Library Cache Pin

  • 라이브러리 캐시 객체에 대한 검색/변경시 라이브러리 캐시 객체에 획득하는 락이다.
  • 라이브러리 캐시 락을 획득한 후에 라이브러리 캐시 객체에 추가적인 작업이 필요할 때 획득한다.
  • 특정 프로시저나 SQL을 검색할 때 라이브러리 캐시 락을 shared 모드로 획득한 '후에' 라이브러리 캐시 pin을 shared 모드로 획득한다.

[3] 라이브러리 캐시 최적화를 위한 개발자의 노력

  • 바인드 변수 사용으로 하드파싱 감소시키기 위해 커서 공유 가능한 형태의 SQL을 작성한다.
  • 라이브러리 캐시에서 SQL 찾는 비용 감소시키기 위해 세션 커서 캐싱 기능을 활용한다.
  • Parse Call 발생을 감소시키기 위해 애플리케이션 커서 캐싱 기능을 이용한다.
profile
도광양회(韜光養晦) ‘빛을 감추고 어둠속에서 힘을 기른다’

0개의 댓글