오라클 성능 고도화 원리와 해법 I (2009년)
DB 버퍼 캐시 0 0 4,046

by 구루비 Buffer Cache [2009.10.09]


DB 버퍼 캐시란?

사용자가 입력한 데이터를 데이터파일에 저장하고 이를 다시 읽기 위해 거쳐가는 Process

1. 블록 단위 I/O

  • 오라클에서 I/O는 블록 단위로 액세스를 하며 아래의 경우에 발생
    • 메모리 버퍼 캐시에서 버퍼 블록을 액세스 할때 블록 I/O
    • 데이터파일에 저장된 데이터 블럭을 DB 버퍼 캐시로 적재할때 블럭 I/O
    • 캐시에서 변경된 블록을 다시 데이터파일에 저장할 때 블럭 I/O
  • Single vs Multi
    • Single Block Read : 인덱스를 경유한 테이블 액세스 시
    • Multi Block Read : TABLE FULL SCAN 할 때, DBWR가 데이터파일에 기록할 때
  • 블록 단위 액세스란?
    • 하나의 레코드에서 하나의 컬럼만 읽고자 하더라도 레코드가 속한 블록 전체를 읽게 됨을 의미

2. Buffer Cache 구조

  • 'DB Buffer Cache'는 아래와 같이 바둑판처럼 표현을 할 수 있는 데 이 중 읽고자 하는
    버퍼 블록을 어떻게 찾아 가는가?

  • 'DB Buffer Cache'는 'Hash Table' 자료구조로 관리가 되며 'Hash Table'의 Bucket에 있는
    'Hash Chain'으로 'Buffer Header'를 'Linked List'로 연결하여 데이터를 SCAN 방식으로 찾아
    그 'Header'의 'Pointer'를 이용해 다시 버퍼 블록을 찾는 구조

  • Hash Table이란?
    • 'Hash Table'을 쉽게 이해하려면 전화번호를 적는 수첩을 연상하면 된다.
      전화번호 수첩에는 이름의 성 자음을 카타고리로 분류하여 그곳에 이름과 전화번호를 저장하면
      이후에 전화번호를 찾을 ? 성의 자음 위치에서 찾으면 금방 찾을 수 있는 것처럼, 해시 테이블도
      어떤 기준값으로 나눈 버킷에 데이터를 묶어서 그 부분만 찾으면 쉽게 찾을 수 있다.
    • 하지만 같은 버킷으로 관리한다 하더라도 버킷 내에서는 정렬이 되지 않아 처음부터 끝까지 찾는
      SCAN 방식으로 찾아야 한다.
    • 그래도 SCAN 방식으로 찾는 시간이 워낙 빨라 각 버킷마다 일정하게 엔트리 개수를 유지할 수 있다면
      해싱 속도를 빠르게 유지할 수 있다.

  • 'DB Buffer Cache'를 찾아가는 과정
    • 맨 처음 데이터 블록 주소(DBA, Data Block Address)를 해시 함수에 넣고 해시값을 리턴 받는다.
      예를들어 '신승우'라고 할 경우 해시 함수에 넣고 'ㅅ' 값을 리턴 받는다.
    • 해시 값이 같은 블록들을 같은 버킷에 연결리스트(Linked List) 구조로 연결한다. 여기서 연결리스트를
      Hash Chain이라고 한다. '신승우', '박정민', '이승훈' 이라면 각각 'ㅅ', 'ㅂ', 'ㅇ' 카타고리에 위부터
      아래로 적어 내려간다.
    • 만약 해당 버킷에서 체인을 따라 스캔하다가 거기서 찾아지면 바로 읽고, 찾지 못하면 디스크에서 읽어
      해시 체인에 연결한 후 읽는다.

3. Cache Buffer Chain

  • 'Cache Buffer Chain'은 Latch에 의해 보호된다. 'DB Buffer Cache'는 SGA에 존재하므로 여러 프로세스가
    동시에 액세스를 할 수 있기 때문에 이를 방지하고자 일종의 Lock 매커니즘인 래치를 사용한다.
  • 래치 개수 확인

SELECT *
FROM   V$VERSION
;

BANNER
-----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bit
PL/SQL Release 10.2.0.3.0 - Production

SELECT COUNT(*)
FROM   V$LATCHNAME
;

  COUNT(*)
----------
       388

  • 하나의 래치는 여러개의 해시 체인을 동시에 관리한다.

-- 1. 전체 버킷 개수 확인
SELECT A.KSPPINM  NAME,
       B.KSPPSTVL VALUE,
       B.KSPPSTDF DEF_YN,
       A.KSPPDESC DESCRIPTION
FROM   X$KSPPI  A,
       X$KSPPSV B
WHERE  A.INDX = B.INDX
AND    LOWER(A.KSPPINM) LIKE '%_db_block_hash_buckets%'
ORDER  BY 1
;

NAME                   VALUE   DEF_YN DESCRIPTION
---------------------- ------- ------ ---------------------------------------
_db_block_hash_buckets 1048576 TRUE   Number of database BLOCK hash buckets
;

-- 2. cache buffers chains 개수
SELECT COUNT(*)
FROM   v$latch_children
WHERE  NAME = 'cache buffers chains'
;

  COUNT(*)
----------
     32768

-- 3. 하나의 래치가 관리하는 버킷 수
1,048,576 / 32,768 = 32

  • 9i 이후부터는 Cache Buffer Chain Latch를 Shared 모드로 공유할 수 있어 경합을 줄일 수 있음
    • 하지만 SELECT를 할 때도 여전히 경합이 발생하는데 그 이유는 'Buffer Lock'과 관련이 있음
    • 읽기작업을 위해 Shared 모드로 래치를 획득한 경우, 실제 버퍼를 읽는 과정에서 'Buffer Lock'을
      Shared 모드로 획득해야 하는데 이 과정에서 헤더의 정보를 일부 변경함
    • 그러므로 'Buffer Lock'을 획득하는 경우에는 래치를 Exclusive 모드로 변경해야 하고 'Buffer Lock'을
      해지하는 경우에도 래치를 Exclusive하게 획득해야 함(Buffer Pin)
    • 이 과정에서 경합이 발생하고 'latch : cache buffers chains' 이벤트를 대기함

4. Cache Buffer LRU Chain

  • 버퍼 헤더는 해시 체인 뿐 아니라 LRU 체인에 의해서도 연결됨
  • 이 때 LRU 리스트를 보호하기 위해 사용하는 래치를 'cache buffers lru chain' 래치하고 함

버퍼 상태

1. Free Buffer

  • 인스턴스 기동 후 아직 데이터가 읽히지 않아 비어 있는 상태
    또는 데이터가 담겼지만 데이터파일과 서로 동기화되 있는 상태여서 언제든지 덮어 써도 무방한 버퍼 블록
  • 오라클이 데이터 파일로부터 새로운 데이터 블록을 로딩하려면 먼저 Free Buffer를 확보해야 함
  • Free 상태인 버퍼에 변경이 발생하면 그 순간 Dirty 버퍼로 상태가 변경

2. Dirty Buffer

  • 버퍼에 캐시된 이후 변경이 발생됐지만 아직 디스크에 기록되지 않아 데이터 파일 블록과 동기화가 필요한 버퍼 블록
  • 이 버퍼 블록들이 다른 데이터 블록을 위해 재사용되려면 디스크에 먼저 기록되야 하며, 기록되는 순간 Free Buffer로 변경

3. Pinned Buffer

  • 읽기 또는 쓰기 작업을 위해 현재 액세스되고 있는 버퍼 블록

문서에 대하여

참고자료

"코어 오라클 데이터베이스 스터디 모임" 에서 2009년에 "오라클 성능 고도화 원리와 해법 I " 도서를 스터디하면서 정리한 내용 입니다.

- 강좌 URL : http://www.gurubee.net/lecture/3002

- 구루비 강좌는 개인의 학습용으로만 사용 할 수 있으며, 다른 웹 페이지에 게재할 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^

- 구루비 강좌는 서비스 제공을 위한 목적이나, 학원 홍보, 수익을 얻기 위한 용도로 사용 할 수 없습니다.

댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입