간단명료

01. 오라클 아키텍처 본문

오라클 성능 고도화 원리와 해법1

01. 오라클 아키텍처

FeelGoood 2022. 2. 16. 20:21

01. 기본 아키텍처

오라클은 데이터베이스(데이터를 저장하는 파일 집합)와 이를 액세스하는 프로세스 사이에 SGA(System Global Area 또는 Shared Global Area)라고 하는 메모리 캐시 영역을 두고 있다.
많은 프로세스가 동시에 데이터를 액세스하기 때문에 사용자 데이터를 보호하는 Lock은 물론 공유 메모리 영역인 SGA상에 위치한 데이터 구조에 대한 액세스를 직렬화하기 위한 LOCK 메커니즘(=래치, Latch)도 필요해진다.
오라클은 블록단위로 읽고, 저장할 때도 변경이 발생한 블록만 찾아 블록 단위로 저장한다.


위 그림은인스턴스(SGA공유메모리 영역과 이를 액세스하는 프로세스 집합을 합친 의미.)를 표현한 것이다.
서버프로세스 : 전면에서 사용자가 던지는 명령 처리.
-> SQL을 파싱하고 필요하면 최적화 수행하며, 커서를 열어 SQL을 실행하면서 블록을 읽고, 읽은 데이터를 정렬해서 클라이언트가 요청한 결과집합을 만들어 네트워크를 통해 전송하는 일련의 작업.
백그라운드프로세스 : 보이지 않지만 뒤에서 묵묵히 역할 수행.

오라클에 접속하는 애플리케이션을 구축할 때 반드시 커넥션풀기능이 필요하다. 한번 커넥션을 맺으면 작업을 완료하더라도 이를 해제하지 않고 애플리케이션 서버에 Pooling하고 있다가 반복 재사용한다. 소프트웨어세계에서 가장 중요한 재사용성은 데이터베이스 성능 튜닝의 핵심 원리다.


02. DB 버퍼 캐시(DB Buffer Cache)

빠른 데이터 입출력을 위해 SGA공유 메모리를 이용하는데, 사용자가 입력한 데이터를 데이터파일에 저장하고 이를 다시 읽는 과정에서 거쳐 가는 캐시영역은 SGA구성요소 중 DB버퍼캐시 이다.

(1) 블록단위 I/O

모든 처리를 블록 단위로 한다. 블록 단위로 읽는다는 의미는, 하나의 레코드에서 하나의 컬럼만을 일고자 하더라도 레코드가 속한 블록 전체를 읽게 됨을 의미한다.

(2) 버퍼 캐시 구조

DB 버퍼 캐시는 해시테이블 구조로 관리된다.
데이터블록주소(DBA, Data Block Address) : DB버퍼 캐시 내에서 데이터 블록을 해싱하기 위해 사용되는 키 값.
해시함수에 DBA를 입력해 리턴받은 해시 값이 같은 블록들을 같은 해시 버킷연결 리스트(Linked List)구조로 연결한다. 각각의 연결리스트를 해시체인(Hash Chain)이라고 한다.

버퍼헤더만 해시체인에 연결되며, 실제 데이터 값이 필요해지면 버퍼헤더에 있는 포인터를 이용해 다시 버퍼블록을 찾아가는 구조다.

(3) 캐시 버퍼 체인

각 해시체인은 래치(Latch)에 의해 보호된다. DB버퍼캐시는 공유메모리영역인 SGA 내에 존재하므로 여러 프로세스에 의한 동시 액세스가 일어날 가능성이 크다. 따라서 같은 리소스에 대한 액세스를 반드시 직렬화(Serializaition)해야하고, 이를 위해 구현된 일종의 Lock 메커니즘을 래치(Latch)라고 부른다. 래치를 흭득한 프로세스만이 그 래치에 의해 보호되는 자료구조로의 진입이 허용된다. 래치 종류는 엄청나게 많이 있다.(11g기준496개)

(4) 캐시 버퍼 LRU(Least Recently Used) 체인

버퍼헤더는 해시체인 뿐 아니라 LRU체인에 의해서도 연결돼 있다. DB 버퍼 캐시는 메모리 공간이 한정적이어서 사용빈도가 높은 데이터 블록들 위주로 구성될 수 있도록 LRU알고리즘을 사용해 관리된다.


03. 버퍼 Lock

(1) 버퍼 Lock이란?

DB 버퍼 캐시 내에서 버퍼 블록을 찾은 후 쥐고 있던 래치를 빨리 해제하지 않으면 하나의 cache buffer chains 래치에 여러 개의 해시 체인이 달리게 되어 래치에 대한 경합 발생 가능성이 증가하게 된다. 이를 막기 위해 캐시된 버퍼 블록을 읽거나 변경하려는 프로세스는 먼저 버퍼 헤더로부터 버퍼 Lock을 흭득 후 바로 래치를 해제해야 한다.
해시 체인 래치를 흭득하고 목적한 버퍼를 찾았는데 다른 프로세스가 버퍼 Lock을 Exclusive모드(변경)로 점유한 채 갱신 중이라면 래치를 쥔 채 기다릴 수 없다. 이럴 때는 버퍼 헤더에 있는 버퍼 Lock 대기자 목록(Waiter List)에 자신을 등록하고 일단 래치는 해제한다. 이때, 버퍼 Lock 대기자 목록에 등록 돼 있는 동안 buffer busy waits 대기 이벤트가 발생한다. 이 후 버퍼 Lock이 해제되면 버퍼 Lock을 흭득하고 작업을 진행한다.
작업 완료 후에 버퍼 Lock을 해제해야하는데, 이때도 ㅂ퍼 헤더를 액세스하려는 다른 프로세스와 충돌이 생길 수 있으므로 해당 버퍼가 속한 체인 래치를 다시 한 번 흭득한다. 버퍼 Lock을 해제하고 래치를 해제해야 비로소 버퍼 블록 읽기가 완료된다.

(2) 버퍼 핸들

버퍼 Lock을 설정하는 것은 자신이 현재 그 버퍼를 사용중임을 표시해 두는 것으로서 그 버퍼 헤더에 Pin을 걸었다고도 표현한다. 버퍼 Lock을 다른 말로 버퍼 Pin 또는 Pinned 버퍼 라고 한다. 변경 시에는 하나의 프로세스만, 읽기작업 시에는 여러 개 프로세스가 동시에 Pin을 설정할 수 있다.
버퍼 헤더에 Pin을 설정하려고 사용하는 오브젝트를 버퍼핸들(Buffer Handle)이라고 한다. 버퍼 핸들도 공유된 리소스이므로 또 다른 래치가 필요해지는데, cache buffer handles 래치가 그것이다.

(3) 버퍼 Lock의 필요성

(4) 버퍼 Pinning

버퍼 Pinning : 버퍼를 읽고 나서 버퍼 Pin을 즉각 해제하지 않고 데이터베이스 Call이 진행되는 동안 유지하는 기능.
같은 블록을 반복적으로 읽을 대 버퍼 Pinning을 통해 래치 흭등 과정을 생략하다며 논리적 블록 읽기(Logical Reads) 횟수를 획기적으로 줄일 수 있다. 같은 블록을 재방문할 가능성이 큰 몇몇 오퍼레이션을 수행할 때만 사용한다.
버퍼 Pinning은 하나의 데이터베이스 Call(Parse Call, Execute Call, Fetch Call) 내에서만 유효하다. Call이 끝나고 사용자에게 결과를 반환하고 나면 Pin은 해제돼야 한다. 따라서 첫 번째 Fetch Call에서 Pin된 블록은 두 번째 Fetch Call에서 다시 래치 흭득 과정을 거쳐 Pin 되야 한다.


04. Redo

오라클은 데이터파일과 컨트롤 파일에 가해지는 모든 변경사항을 하나의 Redo로그엔트리로서 Redo 로그에 기록한다.(물론 데이터파일에 대한 변경은 캐시된 블록 버퍼를 통해 이루어진다.) Redo 로그는 Onlined Redo와 Archived(=Offline) Redo 로그로 구성된다.
Online Redo : Redo 로그 버퍼에 버퍼링된 로그 엔트리를 기록하는 파일로서, 두 개 이상의 파일로 구성된다. 현재 사용중인 Redo 로그 파일이 꽉 차면 다음 Redo 로그 파일로 로그 스위칭(log switching)이 발생하며, 모든 Redo 로그 파일이 꽉 차면 다시 첫 번째 Redo 로그파일부터 재사용하는 라운드로빈(Round-Robin) 방식을 사용한다.
Archived Redo : Online Redo 로그가 재사용되기 전에 다른 위치로 백업해 둔 파일.

Redo 로그는 아래 3가지 목적을 위해 사용된다.

1. Database Recovery(=Media Recovery)
2. Cache Recovery(=Instance Recovery 시 roll forward 단계)
3. Fast Commit

(1) Database Recovery

Redo 로그는 물리적으로 디스크가 깨지는 등이 Media Fail 발생 시 데이터베이스를 복구하기 위해 사용되며, 이떄는 Archiver Redo 로그를 이용하게 된다.

(2) Cache Revoery

모든 데이터베이스 시스템이 버퍼 캐시를 도입하는 것은 I/O 성능 향상을 위함이지만, 버퍼 캐시는 휘발성이다. 따라서 디스크 상의 데이터 블록에 아직 기록되지 않은 상태에서 정전 등이 발생해 인스턴스가 비정상적으로 종료(Instance Crash)되면, 작업내용을 모두 잃게 된다. 이러한 트랜잭션 데이터의 유실에 대비하기 위해 Redo로그를 사용한다.

Instance Crash 발생 후 시스템을 재기동하면

  1. Online Redo 로그에 저장된 기록 사항들을 읽어들여 마지막 체크포인트 이후부터 사고 발생 직전까지 수행되었던 트랜잭션들 재현한다.(->roll forward 단계) 그러면 버퍼 캐시에만 수정하고 데이터파일에는 반영되지 않았던 변경사항들 복구 된다. 이는 트랜잭션의 커밋여부를 불문하고 일단 버퍼캐시를 시스템이 셧다운 되기 이전 상태로 되돌리는 것이다.
    -> Cache Recovery
  2. Cache Recovery가 완료되면 Undo데이터를 이용해 커밋되지 않았던 트랜잭션들을 모두 롤백하는 Transaction Recovery가 진행된다. ->rollback 단계)
  3. roll forward와 rollback 단계를 모두 와료하면 커밋되지 않은 기록사항들은 모두 제거되어 데이터파일에는 커밋에 성공한 데이터만 남게 되며, 데이터베이스는 완전히 동기화된 상태가 된다.

(3) Fast Commit

변경된 메모리 버퍼 블록을 디스크 상의 데이터 블록에 기록하는 작업은 Random 액세스 방식으로 이루어지 때문에 느리기 마련이다. 반면 로그는 Append방식으로 기록하므로 상대적으로 매우 빠르다. 모든 DBMS의 공통적인 메커니즘이다. 그런데 Fast Commit을 구현하는 데 있어 오라클만의 특징적인 기능이 있는데, 바로 Delayed 블록 클린아웃(cleanout, 갱신된 블록에 커밋 정보를 기록하고 Lock을 해제하는 작업)이다.
다른 DBMS 는 Lock 매니저를 통해 로우 Lock을 관리하는 반면 오라클은 Lock매니저 없이 Lock을 해제하려면 갱신했던 블록들을 일일이 찾아다녀야 한다. 따라서 커밋시점에는 Undo 세그먼트 헤더의 트랜잭션 테이블에만 커밋정보를 기록하고, 블록클린아웃은 나중에 수행하도록 한다.

Redo로그버퍼에 기록 후

  1. 3초마다 DBWR 프로세스로부터 신호를 받거나(DBWR은 Dirty 버퍼를 데이터 파일에 기록하기 전에 로그 버퍼 내용을 REdo 로그 파일에 기록하도록 LGWR에게 신호를 보냄)
  2. 로그 버퍼의 1/3이 차거나 기록된 Redo 코드량이 1MB를 넘거나
  3. 사용자가 커밋 또는 롤백 명력을 알릴 때(<-Fast Commit메커니즘의 핵심)
    LGWR 프로세스에 의해 Redo 로그버퍼에 있는 내용을 Redo 로그 파일에 기록한다.

정리해보면, 버퍼캐시에 있는 블록버퍼를 갱신하기 전에 먼저 Redo 엔트리를 로그버퍼에 기록해야하며, DBWR가 버퍼캐시로부터 Dirty 블록들을 디스크에 기록하기 전에 먼저 LGWR가 해당 Redo 엔트리를 모두 Redo 로그 파일에 기록했음이 보장되야 한다.(=Write Ahead Logging)

  1. 사용자가 커밋을 날리면
  2. 서버프로세스는 커밋레코드를 Redo 로그버퍼에 기록하고
  3. LGWR는 이것을 즉시 트랜잭션 로그엔트리와 함께 Redo 로그파일에 저장하고 나서
  4. 커밋을 수행한 트랜잭션에 success code 를 리턴한다.
    여기까지 완료되면 Instance Crash가 발생하더라도 Redo 로그를 이용해 언제든 복구 가능한 상태가 되어 오라클은 안심하고 커밋을 완료할 수 있는 것이다.

05. Undo

과거에는 롤백(Rollback)이라는 용어로 사용.
각 트랜잭션 별로 Undo 세그먼트를 할당해주고(2개 이상의 트랜잭션이 하나의 Undo 세그먼트를 할당 받아 같이 사용할 수 있음) 그 트랜잭션이 발생시킨 테이블과 인덱스에 대한 변경사항들을 Undo 레코드 단위로 Undo 세그먼트 블록에 차곡차곡 기록한다.

Undo 세그먼트에 저장된 정보는 아래 3가지 목적을 위해 사용된다.

  1. Transaction Rollback
  2. Transaction Recovery
  3. Read Consistency ★
  4. 트랜잭션에 의한 변경사항을 최종 커밋하지 않고 롤백하고자할 때
  5. Instance Crash 후 Redo를 이용해 Roll forward단계가 완료되면 최종 커밋되지 않은 변경사항까지 모두 복구되는데, 이때 Undo 세그먼트에 저장된 Undo 데이터를 통해 셧다운 시점에 커밋되지 않았던 트랜잭션들을 모두 롤백한다.
  6. 아래 내용에 자세히 설명.

(1) Undo 세그먼트 트랜잭션 테이블 슬롯

Undo 세그먼트 중 첫 번째 익스텐트, 그중에서도 첫 번째 블록에는 Undo 세그먼트 헤더 정보가 담긴다. Undo 세그먼트 헤더에는 트랜잭션 테이블 슬롯(Transaction Table Slot)이 위치하는데, 각 슬롯에 기록되는 사항들은 아래와 같다.

  1. 트랜잭션ID
  2. 트랜잭션 상태정보(Transaction Status)
  3. 커밋SCN(->트랜잭션이 커밋된 이유)
  4. Last UBA(Undo Block Address, 뒤에 계속 추가하기 위한 일종의 포인터 + 롤백 시 이 체인을 통해 거슬러올라가며 작업 수행)
  5. 기타
    트랜잭션을 시작하려면 먼저 Undo 세그먼트에 있는 트랜잭션 테이블로부터 슬롯을 할당받아야 하며, 할당받은 슬롯에 자신이 현재 Active 상태임을 표시하고서 갱신을 시작한다. 각 DML 오퍼레이션 별로 Undo 레코드에 기록되는 내용은 아래와 같다.
  • Insert : 추가된 레코드의 rowid
  • Update : 변경되는 컬럼에 대한 before image
  • Delete : 지워지는 로우의 모든 컬럼에 대한 before image

insert 또는 delete 시에는 인덱스 하나당 하나의 Undo 레코드가 추가되고, update 시에는 인덱스 하나당 두 개의 Undo 레코드가 추가된다. 인덱스 엔트리를 update 할 때는 내부적으로 delete & insert 방식으로 수행되기 때문이다.

(2) 블록 헤더 ITL 슬롯

Undo 세그먼트 헤더에 트랜잭션 테이블 슬롯이 있다면 각 데이터 블록과 인덱스 블록헤더에는 ITL(Intersted Transaction List)슬롯이 있다. ITL 슬롯에 기록되는 내용은 다음과 같다.

  1. ITL슬롯번호
  2. 트랜잭션ID
  3. UBA(Undo Blcok Address)
  4. 커밋 Flag
  5. Locking 정보
  6. 커밋 SCN(->트랜잭션이 커밋된 경우)
    트랜잭션을 시작하려면 Undo 세그먼트 트랜잭션 테이블로부터 슬롯을 먼저 확보하듯이, 특정 블록에 속한 레코드를 갱신하려면 먼저 블록헤더로부터 ITL 슬롯을 확보해야한다.(3) Lock Byte이제 블록헤더에서 블록으로 내려와서 Lock Byte에 대해 살펴보자. 오라클은 레코드가 저장되는 로우마다 그 헤더에 Lock Byte를 할당해 해당 로우를 갱신 중인 트랜잭션의 ITL슬롯번호를 기록해둔다. 이것이 로우단위(low-lwvel) Lock이며, 오라클은 로우단위Lock과 트랜잭션Lock(=TX Lock)을 조합해서 로우 Lock을 구현하였다.

06. 문장수준 읽기 일관성

문장수준 읽기 일관성은 단일 SQL문이 수행되는 도중에 다른 트랜잭션에 의해 데이터의 추가, 변경, 삭제가 발생하더라도 일관성 있는 결과집합을 리턴하는 것을 말한다.(사례는 p.48 참고)

(2) Consistent 모드 블록 읽기

쿼리가 시작된 시점을 기준으로 데이터를 읽어 들이는 모드.
쿼리가 시작되기 전에 이미 커밋된 데이터만 읽고, 쿼리 시작 이후에 커밋된 변경사항은 읽어들이지 않는다.
오라클은 SCN(System Commit Number)이라고 하는 시간정보를 이용해 데이터베이스의 일관성 있는 상태를 식별하는데, 이는 시스템 전체적으로 공유되는 Global변수라고 이해하면 쉽다. 기본적으로 사용자가 커밋할 때마다 1씩 증가한다. 또는 커밋이 없더라도 오라클 백그라운드 프로세스에 의해 조금씩 증가한다.
SCN은 읽기 일관성과 동시성 제어를 위해 사용되고, 사용된 Redo 로그 정보의 순서를 식별하는 데에도 사용되며, 데이터 복구를 위해서도 사용된다.

(3) Consistent 모드 블록 읽기의 세부원리

오라클에서 수행되는 모든 쿼리는 Global 변수인 SCN 값을 먼저 확인하고 나서 읽기 작업을 시작하는데, 이를 쿼리SCN 또는 스냅샷SCN이라고 한다. 쿼리SCN을 들고 다니면서 읽는 블록마다 블록 SCN과 비교해 읽을 수 있는 버전인지를 판단하는 것이다.
쿼리SCN을 가지고 Consistent 모드로 일ㄲ을 때, 읽는 블록 상태에 따라 어떻게 일관성을 유지하며서 데이터를 읽는지 3가지 경우로 나누어 볼 수 있다.

  • Current 블록SCN <= 쿼리SCN 이고, committed 상태
  • Current 블록SCN > 쿼리SCN 이고, comitted 상태
  • Current 블록이 Active 상태, 즉 갱신이 진행 중인 것으로 표시 돼 있을 때

A. Current 블록SCN <= 쿼리SCN이고, committed 상태

Consistent 모드에서 데이터를 읽을 때는 블록SCN<=쿼리SCN일 때만 읽을 수 있다. 이 때의 블록은 Current블록을 의미하며, Current 블록은 오직 한 개뿐이다. 해당 상태라면 쿼리가 시작된 이후에 해당 블록에 변경이 가해지지 않았다는 것을 의미한다. 이때는 CR블록을 생성하지 않고 Current 블록을 그대로 읽으면 된다.

B. Current 블록SCN > 쿼리SCN 이고, committed 상태

이 상태에는 해당 블록에 변경이 가해지고 커밋되었다는 것을 의미한다.

블록 원본에 해당되는 Current 블록의 SCN이 쿼리 SCN보다 크면 블록 복사본에 해당하는 CR블록을 먼저 생성(CR Cloning)한다(②). 이를 자신이 읽을 수 있는 과거 버전(쿼리 SCN보다 낮은 마지막 committed 시점)으로 되돌린다(③). CR블록을 과거 상태로 되돌릴 때 사용하려고 Undo 정보가 필요한 것이며, ITL슬롯에서 UBA(Undo Block Address)가 가리키는 Undo블록을 찾아가 변경 이전 값을 읽는다. 최종적으로 완성된 버전의 CR블록은, 블록SCN <= 쿼리SCN이면서 커밋되지 않은 내용은 전혀 포함하지 않은 상태가 된다. 해당 과정에서 Snapshot too old가 발생할 수 있는데 원인과 해결책은 9절에서 자세히 다룬다.

C. Current블록이 Active상태, 즉 갱신이 진행 중인 것으로 표시돼 있을 때

Active상태의 블록일 때는 일단 트랜잭션 테이블로부터 커밋정보를 가져와 블록 클린아웃(트랜잭션에 의해 설정된 로우 Lock을 해제하고 블록 헤더에 커밋 정보를 기록)을 시도한다. 그 결과, 쿼리SCN 이전에 이미 커밋된 블록으로 확인된다면 A 경우처럼 그 블록을 그대로 읽으면 된다. 쿼리SCN 이후에 커밋된 블록으로 확인되거나, 커밋되지 않아 아직 클린아웃할 수 없다면 B경우처럼 CR Copy를 만들어 쿼리SCN보다 낮은 마지막 committed 상태로 되돌린 후 읽어야 한다.(p.58 참고)


07. Consistent vs Current 모드 읽기★

SQL튜닝할 때 트레이스를 통해 항상 접하게 되는 이 두 가지 블록 읽기 모드의 차이점은 굉장히 중요하다.

(1) Consistent 모드 읽기와 Current 모드 읽기의 차이점

)

Consistent 모드 읽기(gets in consistent mode) : SCN 확인 과정을 거치며 쿼리가 시작된 시점을 기준으로 일관성 있는 상태로 블록을 엑세스하는 것을 말한다.
(SQL트레이스-query, AutoTrace-consistent gets이 Consistent 모드에서 읽은 블록 수)
Current 모드 읽기(gets in current mode) : SQL문이 시작된 시점이 아니라 데이터를 찾아간 바로 그 시점의 최종 값을 읽으려고 블록을 액세스하는 것을 말한다. 블록SCN이 쿼리SCN보다 높고 낮음을 따지지 않으며, 그 시점에 이미 커밋된 값이라면 그대로 받아들이고 읽는다.
(SQL트레이스-current, AutoTrace-db block gets 항목이 Current모드에서 읽은 블록 수)

  1. DML문 수행 시 주로 나타나며, 인덱스가 많을수록 더 많이 나타난다.
  2. select for update
  3. 디스크 소트가 필요할 정도로 대량의 데이터를 정렬할 때
    Current 모드 읽기가 나타난다.(2) Consistent 모드로 갱신할 때 생기는 현상p.64 참고(3) Current 모드로 갱신할 때 생기는 현상p.65 참고(4) Consistent 모드로 읽고, Current 모드로 갱신할 때 생기는 현상p.67 참고(5) Consistent 모드로 갱신대상을 식별하고, Crrent 모드로 갱신p.69 참고(6) 오라클에서 일관성 없게 값을 갱신하는 사례p.73 참고

08. 블록 클린아웃(Block Cleanout)

블록 클린아웃은 트랜잭션에 의해 설정된 로우 Lock을 해제하고 블록 헤더에 커밋 정보를 기록하는 오퍼레이션이다. 앞에서 설명했듯이 오라클에서 로우 단위 Lock은 레코드의 속성(Lock Byte)으로 관리되며, 이는 로우 헤더로부터 블록 헤더에 있는 ITL엔트리를 가리키는 포인터다.
사용자가 트랜잭션을 커밋하면 블록 클린아웃까지 완료해야 완전한 커밋이라고 할 수 있는데, 오라클은 대량의 갱신 작업이 있고 나서는 블록들을 일일이 찾아다니며 클린아웃을 수행하지 않고(시간이 오래걸리기 때문) 커밋 정보를 트랜잭션 테이블에만 기록하고 빠르게 커밋을 끝내 버린다.

(1) Delayed 블록 클린아웃

트랜잭션이 갱신한 블록 개수가 총 버퍼 캐시 블록 개수의 1/10을 초과할 때 사용한다. 커밋 이후 해당 블록을 액세스하는 첫 번째 쿼리에 의해 클린아웃이 이루어지며, 아래와 같은 작업을 수행한다.
① ITL 슬롯에 커밋 정보 저장
② 레코드에 기록된 Lock Byte 해제
③ Online Redo 에 Logging

(2) 커밋 클린아웃(=Fast 블록 클린아웃)

만약 모든 클린아웃을 Delayed 블록 클린아웃 방식으로 처리한다면 select 시에 블록을 클린아웃하는 일이 번번히 발생한다. 트랜잭션이 갱신한 블록 개수가 버퍼 캐시 블록 개수의 1/10을 초과하지 않을 때는 커밋 시점에 곧바로 블록 클린아웃을 수행한다.
커밋 시점에는 ITL슬롯에 커밋 정보만 저장하고 로우 헤더에 기록된 Lock Byte는 해제하지 않는다.(로깅을 수행하지 않기 위해서다 즉, 커밋 클린아웃 시에는 Online Redo에 로그를 남기지 않는다. +이미 완전한 커밋 정보가 ITL에 기록돼 있기 때문) 그러고 나서 해당 블록을 갱신하려고 Current 몯로 읽는 시점에(ITL 슬롯이 필요해지므로) 비로소 Lock Byte를 해제하고 완전한 클린아웃을 수행한다.

(3) ITL과 블록 클린아웃

<블록 dump내용>

슬롯 내용
0x01 Fast클린아웃 상태. 로우헤더에 Lock Byte가 해제되지 않은 상태(Lck=1)에서 ITL 슬롯에 커밋 SCN이 찍혀 있지만 Fast 클린아웃 상태임을 표시하기 위해 Scn wrap 대신 fsc라고 표시돼 있고, 커밋 Flag에는 U가 표시돼 있기 때문. 해당 상태는 곧바로 재사용될 수 없다. 쓰기 작업을 위해 블록이 읽히는 순간 Lock Byte를 해제하고 나서야 재사용이 가능하다. 그럼 2번슬롯(0x02)와 같은 상태로 바뀌며, 표시되는 내용이 Delayed 블록 클린아웃에 의해 클린아웃된 경우와 같다.
0x02 커밋 Flag가 C로 표시돼 있어 ITL이 언제든 재사용 가능하며, 로우 헤더로부터 Lock Byte가 해제된 상태다. 여기 찍힌 커밋 SCN은 정확한 커밋 시점 정보다.
0x03 Lock Byte가 완전히 해제된, 완전히 클린아웃된 상태고 ITL도 언제든 재사용 가능하지만, 여기에 찍힌 SCN은 '추정된 커밋 SCN(upper bound commit number)'정보다. 이는 커밋 Flag가 C-U-인 것을 통해 알 수 있다. Snapshot too old에서 설명한다.

09. Snapshot too old

728x90
반응형
Comments