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
- 읽기 또는 쓰기 작업을 위해 현재 액세스되고 있는 버퍼 블록
문서에 대하여
참고자료