06. 문장수준 읽기 일관성
(1) 문장수준 읽기 일관성이란?
- 단일 SQL문이 수행되는 도중에 다른 트랜잭션에 의해 데이터의 추가, 변경, 삭제가 발생하더라도 일관성 있는 결과집합을 리터하는 것.
- 타DBMS는 모두 로우 Lock을 사용해 Dirty Read를 방지. 읽기 작업에 대해 Shared Lock을 사용함으로써, Exclusive Lock이 걸린 로우를 읽지 못하도록 한다.
<사례1, 2 p.48~51 참고>
(2) Consistent 모드 블록 읽기 <p.52 그림 1-14 참고>
- 오라클은 쿼리가 시작된 시점을 기준으로 데이터를 읽는다. 쿼리가 시작되기 전에 이미 커밋된 데이터만 읽고, 변경이 발생한 블록을 읽을때는 현재의
Current 블록으로부터 CR 블록을 생성해서 쿼리가 시작된 시점으로 되돌린 후 그것을 읽는다. (다중 버전 읽기 일관성 모델 : Multi Version Read Consistency Model)
Current 블록 : 디스크로부터 읽혀진 후 사용자의 갱신사항이 반영된 최종 상태의 원본 블록
CR 블록 : Current 블록에 대한 복사본. CR블록은 여러 버전이 존재할 수 있지만 Current 블록은 오직 한 개뿐이다. - 오라클은 SCN(System Commit Number)이라고 하는 시간정보를 이용해 테이터베이스의 일관성 있는 상태를 식별.
SCN은 읽기 일관성과 동시성 제어를 위해 사용되고, 생성된 Redo 로그 정보의 순서를 식별하는 데에도 사용되며, 데이터 복구를 위해서도 사용된다. - 블록 SCN : 블록이 마지막으로 변경된 시점 정보를 식별하기 위해 모든 블록 헤더에 SCN정보를 관리.(커밋 SCN과는 별도로 관리)
{info}
RAC환경에서는 Share모드의 Current 블록이 여러 노드에 동시에 캐싱돼 있을 수 있다. 하지만 Exclusive 모드의 Current 블록은 오직 한 노드에만 존재할 수 있다.
{info}
(3) Consistent 모드 블록 읽기의 세부원리
- 오라클에서 수행되는 모든 쿼리는 Global 변수인 SCN(System Commit Number)값을 먼저 확인하고 읽기 작업 시작(쿼리 SCN, 스냅샷 SCN)
- 읽는 블록마다 블록 SCN과 비교해 읽을 수 있는 버전인지를 판단
A. 'Current 블록 SCN <= 쿼리SCN' 이고, commited 상태
- 쿼리가 시작된 이후에 해당 블록에 변경이 가해지지 않았다는 것을 의미. CR블록을 생성하지 않고 Current 블록을 그대로 읽는다.
- Consistent 모드에서 데이터를 읽을 때는 블록 SCN(System Change Number)이 쿼리 SCN(System Commit Number)보다 작거나 같은 블록만 읽을 수 있다.
- 이때의 블록은 Current 블록을 의미하며, Current 블록은 오직 한 개뿐이다. 데이터 갱신은 항상 Current 블록에서만 발생.
B. 'Current 블록 SCN > 쿼리SCN' 이고, commited 상태
- 쿼리가 시작된 이후 해당 블록에 변경이 가해지고 커밋되었다는 것을 의미. <p.55 그림 1-15 참고>
1) 블록 원본에 해당하는 Current 블록의 SCN이 쿼리 SCN보다 크다.
2) 블록 복사본에 해당하는 CR블록을 먼저 생성(CR Cloning)
3) 자신이 읽을 수 있는 과거 버전(쿼리 SCN보다 낮은 마지막 commited 시점)으로 되돌린다.(ITL 슬록에서 UBA(Undo Block Address)가 가리키는 Undo 블록 이용) - Undo 레코드를 읽어 CR 블록을 한 단계 이전 상태로 되돌렸는데, 거기에 커밋되지 않은 변경사항이 포함돼 있거나 블록 SCN이 높다면 다시 ITL 슬롯에 있는
UBA가 가리키는 Undo 레코드를 찾아 블록을 이전 상태로 되돌리는 작업을 계속한다. - 최종적으로 완성된 버전의 CR블록은, 블록 SCN이 쿼리 SCN보다 작으면서 커밋되지 않은 내용은 전혀 포함하지 않은 상태가 된다.
- UBA를 통해 계속적인 롤백이 가능한 것은 ITL에 대한 변경내역까지도 Undo 레코드에 기록되기 때문.
- 같은 레코드를 계속 변경할 때, 그 레코드를 조회하는 다른 세션에서의 CR블록 읽기 횟수도 계속 증가하는 것을 통해 확인 가능.
- 10g부터는 IMU(In-Memory Undo) 메커니즘 작동하므로 CR 롤백을 위해 Undo를 참조하지 않고 Shared Pool 내의 IMU Pool에 저장된 값을 이용(IMU CR rollback)
- CR 블록을 과거 상태로 되돌리는 과정에서 필요한 Undo 정보가 덮어 쓰여져 계속 롤백을 진행할 수 없을 때 'Snapshot too old(ora-1555)' 발생
- Delayed 블록 클린아웃' 과정에서 트랜잭션 테이블 슬롯이 이미 다른 트랜잭션에 의해 재사용되는 바람에 현재 읽고자 하는 클린아웃되지 않은 블록의 정확한
커밋 시점 정보를 확인할 수 없을 때도 Snapshot too old' 발생.(8, 9절에서 설명)
- A세션
SQL> alter session set "_in_memory_undo" = false;
SQL> update emp set sal = sal + 1 where empno = 7900;
혹은
SQL> declare
2 l_cnt number;
3 begin
4 for l_cnt in 1..1000
5 loop
6 update emp set sal = sal + 1 where empno = 7900;
7 end loop;
8 end;
9 /
PL/SQL 처리가 정상적으로 완료되었습니다.
SQL> update emp set sal = sal + 1 where empno = 7900;
1 행이 갱신되었습니다.
SQL> /
1 행이 갱신되었습니다.
SQL> /
1 행이 갱신되었습니다.
- B세션
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
926 consistent gets
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
927 consistent gets
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
928 consistent gets
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
929 consistent gets
IMU(In-Memory Undo)
- 10g에 추가된 기능으로 Hidden 파라미터 '_in_memory_undo'와 '_imu_pools'에 의해 제어
- 이 파라미터가 TRUE면 오라클은 Undo 데이터를 Undo에 세그먼트가 아닌 Shared Pool 내의 미리 할당된 IMU Pool(KTI-Undo)에 생성
- 각 Pool은 하나의 트랜잭션에 전용으로 할당되며 im memory undo latch에 의해 보호
- IMU Pool이 다 차면 그때까지 저장해 둔 Undo 데이터를 Undo 세그먼트로 일괄 기록하며(IMU Flush), 이후 계속 발생하는 Undo 데이터는 예전처럼 Undo 세그먼트에 저장
- IMU는 작은 트랜잭션을 위해 고안된 기능이며, Undo 세그먼트 헤더 블록과 Undo 세그먼트 블록 버퍼에 대한 래치 경합 및 Pinning을 줄일 수 있다.
Please enter THE PARAMETER : _imu_pools
NAME VALUE ISDEFAULT ISSES_MODIFIABLE ISSYS_MODIFIABLE ISMODIFIED ISADJUSTED DESCRIPTION
-
--
-
-
_imu_pools 3 TRUE false false false false in memory undo pools
Please enter THE PARAMETER : _in_memory_undo
NAME VALUE ISDEFAULT ISSES_MODIFIABLE ISSYS_MODIFIABLE ISMODIFIED ISADJUSTED DESCRIPTION
-
--
-
---
_in_memory_undo TRUE TRUE true immediate false false Make in memory undo for top level transactions
C.'Current 블록이 Active상태, 즉 갱신이 진행 중인 것으로 표시'돼 있을때
- 읽으려는 레코드에 Lock Byte가 설정돼 있는데, ITL에 아직 커밋 정보가 기록되지 않았다면 현재 갱신이 진행중(Active)인 것으로 인식할 수 있다.
- 오라클은 커밋 시 항상 곧바로 블록을 클린아웃(트랜잭션에 의해 설정된 로우 Lock을 해제하고 블록 헤더에 커밋 정보를 기록)하지는 않는다.
따라서 Active 상태의 블록일 때는 일단 트랜잭션 테이블로부터 커밋정보를 가져와 블록 클린아웃을 시도한다. - 쿼리 SCN 이전에 이미 커밋된 블록 : A경우처럼 그 블록을 그대로 읽는다.
- 쿼리 SCN 이후에 커밋된 블록으로 확인되거나, 커밋되지 않아 아직 클린아웃할 수 없는 경우 :
B경우처럼 CR Copy를 만들어 쿼리 SCN보다 낮은 마지막 Committed 상태로 되돌린 후 읽는다.
<A, B, C 상황 예시는 p.58 ~ p.61 참고>
DBA당 CR 개수 제한
- 하나의 데이터 블록마다 6개까지만 CR Copy를 허용. '_db_block_max_cr_dba' 파라미터로 제어.
- CR Copy는 LRU 리스트 상에서 항상 LRU end쪽에 위치하기 때문에 Free 버퍼가 필요할 때 1순위로 밀려난다.
문서에 대하여
- 최초작성자 : 김종원
- 최초작성일 : 2009년 10월 23일
- 이 문서는 오라클클럽 코어 오라클 데이터베이스 스터디 모임에서 작성하였습니다.
- {*}이 문서의 내용은 (주)비투엔컬설팅에서 출간한 '오라클 성능 고도화 원리와 해법I'를 참고하였습니다.*