본문
(1) 버퍼 Lock(버퍼 Pin)이란?
- 버퍼 Lock을 설정하는 것은 자신이 현재 그 버퍼를 사용중임을 표시해 두는 것 (버퍼 헤더에 Pin을 걸었다고도 표현함)
- 두개 이상의 프로세스가 동시에 버퍼 내용을 읽고 쓴다면 문제가 생긴다.
* 이를 막기 위해 캐시된 버퍼 블록을 읽거나 변경하려는 프로세스는 먼저 버퍼 헤더로부터 버퍼 Lock을 획득해야 한다.
* 버퍼 Lock을 획득했다면 래치를 바로 해제
* 블록을 읽고 씀 (버퍼 Lock을 획득했으므로 안전함)
- 버퍼 Lock의 모드
* Shared 모드 : 버퍼 내용을 읽기만 할 때
* Exclusive 모드 : 버퍼 내용을 변경할 때
※ select 문이더라도 블록 클린아웃이 필요 할 때는 버퍼 내용을 변경하는 작업이므로 Exclusive모드로 Lock을 설정
※ 블록 클린아웃 : 트랜잭션에 의해 설정된 로우 Lock을 해제하고 블록 헤더에 커밋 정보를 기록하는 오퍼레이션
- 해시 체인 래치를 획득 하고 버퍼를 찾았는데,
다른 프로세스가 버퍼 Lock을 Exclusive 모드로 점유한 채 내용을 갱신 중이라면
① 버퍼 헤더에 있는 버퍼 Lock 대기자 목록(Waiter List)에 자신을 등록하고 일단 래치를 해제한다.
② 이때 버퍼 Lock 대기자 목록에 등록되어 있는 동안은 buffer busy waits 대기 이벤트 발생
※ 대기 이벤트 : 일을 계속 진행할 수 있는 조건이 충족될 때까지 수면(Sleep)상태에 빠지는 현상이 발생하는 것
③ 버퍼 Lock이 해제되면 버퍼 Lock을 획득하고 원했던 작업을 진행
④ 읽기/쓰기 작업을 완료하면 해당 버퍼가 속한 체인 래치를 다시 획득 (버퍼 헤더 액세스 시 다른 프로세스와
충돌을 방지하기 위해서)
⑤ 버퍼 Lock 해지
⑥ 래치 해제
(2) 버퍼 핸들
- 버퍼 핸들(Buffer Handle) : 버퍼 헤더에 Pin을 설정하려고 사용하는 오브젝트
- 버퍼 핸들을 얻어 버퍼 헤더에 있는 소유자 목록(Holder List)에 연결시키는 방식으로 Pin을 설정
- 버퍼 핸들 획득
* 버퍼 핸들은 공유된 리소스이므로 버퍼 핸들을 얻으려면 또 다른 래치인 cache buffer handles 래치가 필요
* 각 프로세스마다 _db_handles_cached 개수만큼 버퍼 핸들을 미리 할당해준다.(기본 값 : 5개)
* 각 세션을 이를 캐싱하고 있다가 버퍼를 Pin 할 때 마다 사용
* 그 이상의 버퍼 핸들이 필요할 때만 cache buffer handles 래치를 얻고 추가로 버퍼 핸들을 할당 받음
- 시스템 전체적으로 사용할 수 있는 총 버퍼 핸들 개수는 _db_handles 파라미터에 의해 결정됨
* Processes 파라미터 값 X _db_handles_cache파라미터 값
(3) 버퍼 Lock의 필요성
- 사용자가 데이터를 변경할 때는 DML Lock을 통해 보호, 그것을 담는 블록에 또 다른 Lock을 획득
* 이유 : 오라클이 하나의 레코드를 갱신하더라고 블록 단위로 I/O를 수행하기 때문
ex) 블록 안에 저장된 10개의 레코드를 읽는 짧은 순간 동안 다른 프로세스에 의해 변경이 발생하면
잘못된 결과를 얻게 되기 때문
- 값을 변경하기 전에 레코드에 로우 단위 Lock을 설정(레코드 속성을 변경하는 작업)
⇒ 두 개의 프로세스가 동시에 로우 단위 Lock을 설정하려고 하면 문제가 발생
- 블록 SCN을 변경하거나 ITL 슬롯에 변경을 가하는 등 블록 헤더 내용을 변경하는 작업도 동시에 발생하면
⇒ Lost Update 문제가 생겨 블록 자체의 정합성(Intergrity)이 깨지게 됨
- 그러므로 블록 자체로의 진입을 직렬화해야 하는 것이다
- Pin된 버퍼 블록은, 버퍼 캐시 전체를 비우려고 아래 시스템 명령어를 날리더라도 밀려나지 않는다.
SQL> alter system flush buffer_cache;
- 9i에서는 비공식 적이지만 명령어를 통해 버퍼 캐시를 비울 수 있다.
SQL> alter system set event 'immediate trace name flush_cache' ;
(4) 버퍼 Pinning
- 버퍼 Pinning : 버퍼를 읽고 나서 버퍼 Pin을 즉각 해제하지 않고 데이터베이스 Call이 진행되는 동안 유지하는 기능
- 같은 블록을 반복적으로 읽을 때 버퍼 Pinning을 통해 래치 획득 과정을 생략하므로
논리적 블록 읽기(Logical Reads) 횟수를 줄일 수 있다.
- 모든 버퍼 블록이 버퍼 Pinning을 통해 읽는 것은 아니며, 같은 블록을 재방문할 가능성이 큰 몇몇 작업을 수행할 때만 사용
- v$sysstat, v$sesstat, v$mystat 등을 조회해 보면
┌ 래치 획득 과정을 통해 블록을 액세스할 때는 session logica reads 항목이 증가
└ 래치 획득 과정 없이 버퍼 Pinning을 통해 블록을 곧바로 액세스할 때는 buffer is pinned count 항목 수치가 증가
- 버퍼 Pinning은 하나의 데이터베이스 Call(parse Call, Execute Call, Fetch Call) 내에서만 유효하다.
- 즉, Call이 끝나고 사용자에게 결과를 반환하고 나면 Pin은 해제되어야 한다.
따라서 첫 번째 Fetch Call에서 Pin된 블록은 두 번째 Fetch Call에서 다시 래치 획득 과정을 거쳐 Pin 되어야 한다.
- 인덱스 클러스터링 팩터가 좋다면(=인덱스 레코드가 가리키는 테이블 rowid 정렬 순서가 인덱스 키 값 정렬 순서와
거의 일치한다면)
⇒ 논리적 블록 읽기 회수가 적게 나타난다.
- 11g부터는 NL 조인시 Inner 테이블의 인덱스 루트 블록 뿐 아니라 다른 블록에 대해서도 Pinning을 함으로써 논리적 블록 읽기를 감소 시킴
- DML 수행시 Undo 레코드를 기록하는 Undo Block에 대해서도 Pinning을 적용함
조시형,『오라클 성능 고도화 원리와 해법Ⅰ』, (주)비투엔컨설팅, 2009, pp.30-34
'Oracle > Oracle_성능고도화' 카테고리의 다른 글
[Chapter 01] 오라클 아키텍처 - 02 DB 버퍼 캐시 (0) | 2014.09.22 |
---|---|
[Chapter 01] 오라클 아키텍처 - 01 기본 아키텍처 (0) | 2014.09.22 |