ORACLE - DAY 43

BUMSOO·2024년 10월 8일



Database Buffer Cache

  • Database에서 읽어 들인 block을 메모리에 올려 놓은 영역
  • 물리적인 I/O를 최소화 하기 위한 메모리 영역
  • cache : 곧 사용할 것으로 예상되는 복사본(데이터)을 메모리에 유지함으로써 필요할때 빠르게 접근하는 것을 의미한다.

Database Buffer Cache를 바라볼때

execute 단계

  • library cache lock과 library cache pin을 shared mode로 변환하고 SQL문을 실행한다.

  • 실행계획을 통해서 요청한 블록의 DBA(Data Block Address)와 Block class(종류)에 대해 shared pool의 해시함수에 적용한 결과를 이용해서 hash bucket을 찾는다.

    • hash bucket에는 같은 해시 값을 갖는 버퍼헤더(buffer header)들이 체인(chain)형태로 걸려있다.
    • 버퍼헤더(buffer header)에 대한 메타정보를 가지고 있으면 database buffer cache 영역의 실제 buffer에 대한 포인터값을 가지고 있다.
    • 현재 buffer cache에 올라온 블록의 정보를 shared pool에서 관리하다.
    • 해시값에 해당하는 hash bucket을 검색하기 위해서는 latch를 획득해야한다.
    • 그런데 이미 누군가가 latch를 획득하면 나는 기다려야한다.
    • 이때 발생하는 이벤트 = latch : cache buffers chains
  • latch의 수

    select count(*) from v$latch_children where name='cache buffers chains';

  • latch의 수

select a.ksppinm as parameter,b.ksppstvl as session_value, c.ksppstvl as instance_value 
from x$ksppi a, x$ksppcv b, x$ksppsv c
where a.indx = b.indx
and a.indx = c.indx
and a.ksppinm = '_db_block_hash_latches';

  • bucket의 수
select a.ksppinm as parameter,b.ksppstvl as session_value, c.ksppstvl as instance_value 
from x$ksppi a, x$ksppcv b, x$ksppsv c
where a.indx = b.indx
and a.indx = c.indx
and a.ksppinm = '_db_block_hash_buckets';

  • 하나의 latch가 담당하는 bucket 수는 16384/1024=16

  • 블록 I/O시 hash bucket를 담당하는 cache buffers chains latch를 획득해야한다.

    • 읽기작업(select) : shared mode
    • 쓰기작업(DML) : exclusive mode
    • 이과정에서 경합이 발생하면 latch : cache buffers chains wait event 발생한다.

같은 buffer value값을 바라보는 latch를 (exclusive, shared)로 잡는건 안되지만 (shared, shared)로 잡는건 가능하다. 하나의 latch가 멀티링크가 가능하기 때문이다.

하지만 같은 buffer value의 버퍼헤더를 (shared, shared)로 동시에 바라보는건 안된다.

  • latch를 잡고 hash bucket의 블록에 해당하는 버퍼헤더가 존재하면 해당 블록이 버퍼캐시에 올라와 있는 상태이고 논리적인(logical) I/O 발생

물리적인(physical) I/O발생

  • latch를 잡고 hash bucket의 블록에 해당하는 버퍼헤더가 있는지를 조회해 보고 없으면 물리적인 I/O발생

Working Set(버퍼캐시를 관리)

LRU(Least Recently Used) LIST

  • 가장 최근에 사용되거나 사용하지 않은 버퍼들의 리스트
  • free buffer, 사용중이거나 사용된 버퍼, 아직 LRUW LIST로 옮겨지지 않은 Dirty Buffer(변경된 버퍼)
  • 메인 리스트 : 사용된 버퍼들의 리스트,HOT REGION(자주 사용된 버퍼,MRU), COLD REGION(사용빈도가 낮은 버퍼,LRU)로 구분해서 관리하다.
  • 보조 리스트 : free buffer list, 미 사용된 buffer, DBWR에 의해 기록된 버퍼들의 리스트

LRUW(Least Recently Used Write) List, Dirty List

  • 아직 디스크로 기록되지 않은 변경된 버퍼(Dirty buffer)들을 관리하는 리스트
  • 메인 리스트 : 변경된 버퍼들의 리스트
  • 보조 리스트 : 현재 DBWR에 의해 기록중인 버퍼들의 리스트

물리적인 I/O발생하면 latch를 잡고 free buffer 찾는다.
이때 latch를 못잡으면 latch : cache buffers lru chain wait event 발생한다.

cache buffers lru chain latch

  • lru latch 확인
    • 원래는 18개의 latch가 조회되어야 하는데 뻥튀기가 된거같아서 해당 방법으로는 조회하지 말자.
select count(*) from v$latch_children where name='cache buffers lru chain';

  • lru latch 확인
select a.ksppinm as parameter,b.ksppstvl as session_value, c.ksppstvl as instance_value 
from x$ksppi a, x$ksppcv b, x$ksppsv c
where a.indx = b.indx
and a.indx = c.indx
and a.ksppinm = '_db_block_lru_latches';

  • 실제 latch가 사용하는 영역을 보면 DEFAULT영역만 사용하고 있는걸 확인할 수 있다.
    • 18개의 latch 중에 2개의 latch만 사용하고 있다.
select a.bp_blksz, c.child#, a.bp_name, c.gets
from x$kcbwbpd a, x$kcbwds b, v$latch_children c
where b.set_id between a.bp_lo_sid and a.bp_hi_sid
and c.addr = b.set_latch;

개개의 버퍼풀은 각각의 독립적인 cache buffers lru chain latch를 사용한다.

  • 물리적인 I/O가 발생하면 cache buffers lru chain latch를 잡고 LRU LIST의 보조 리스트 에서 free buffer를 찾는다.

  • 만약 보조 리스트의 버퍼가 모두 사용된 경우에는(즉 free buffer가 없을 경우) 메인리스트의 COLD REGION 제일 뒤에서 부터 free buffer를 찾는다.

  • free scan 도중에 touch count(TCH)가 1이하인 buffer를 free buffer로 사용할 수 있다.

  • free scan 도중에 touch count(TCH)가 2이상인 buffer를 만나면 HOT REGION 앞으로(HEAD) 옮기고 해당 buffer의 touch count(TCH)는 0으로 초기화 시킨다.

  • free scan 도중에 dirty buffer를 발견하면 LRUW LIST 이동시킨다.(후에 DBWR이 디스크로 dirty buffer를 내릴때 편하게 하기 위함)

  • free buffer를 찾게 되면 해당 버퍼에 대해 buffer lock을 exclusive mode로 획득하고 데이터 파일의 블록을 해당 버퍼로 읽어 들인다.

  • 물리적으로 읽어 들이고 있는 중에 다른 세션에서 같은 버퍼헤더을 조회하려고 하는 경우 기다리는 작업이 발생한다. 이때 대기하는 이벤트는 read by other session wait event가 발생한다.

  • 물리적인 I/O 발생시에 LRU 메인 리스트를 40%까지 free buffer를 찾는데, 못찾을 경우에 서버프로세스는 DBWR에게 dirty buffer를 파일에 기록하도록 요청한다.

  • DBWR가 dirty buffer를 파일에 기록할때 까지는 free buffer wait event가 발생한다.

  • LRU LIST free buffer를 40% 스캔

select a.ksppinm as parameter,b.ksppstvl as session_value, c.ksppstvl as instance_value 
from x$ksppi a, x$ksppcv b, x$ksppsv c
where a.indx = b.indx
and a.indx = c.indx
and a.ksppinm = '_db_block_max_scan_pct';

  • touch count 2이상인 버퍼를 만나면 HOT REGION 앞으로(HEAD) 옮기는 기준
select a.ksppinm as parameter,b.ksppstvl as session_value, c.ksppstvl as instance_value 
from x$ksppi a, x$ksppcv b, x$ksppsv c
where a.indx = b.indx
and a.indx = c.indx
and a.ksppinm = '_db_aging_hot_criteria';

  • touch count가 증가되는 주기(초), 마지막 touch count가 증가된 후 3초 이후에 다시 access하게 되면 touch count는 1 증가된다.
select a.ksppinm as parameter,b.ksppstvl as session_value, c.ksppstvl as instance_value 
from x$ksppi a, x$ksppcv b, x$ksppsv c
where a.indx = b.indx
and a.indx = c.indx
and a.ksppinm = '_db_aging_touch_time';


BLOCK I/O에 대한 정리

0개의 댓글