Change Vector

리두와 언두의 핵심, 데이터 블록 변경을 설명하기 위한 메커니즘
안전한 데이터 유지 유지, 읽기/쓰기 경합 최소화, 인스턴스 복구, 미디어 복구, Standby 아키텍처, Flashback 메커니즘, CDC 및 Streams 를 위한 기술요소
※ 필자가 오라클의 가장 중요한 기술요소로 손꼽음

기본적인 데이터 변경

접근방식

  • 데이터를 두 번 기록
    1. 한 본(copy)은 데이터 파일 내 존재
    2. 한 본(copy)은 데이터 파일 내용을 재 생성하는 법을 알려주는 명령어 집합 형태로 리두 로그 파일 내 존재

데이터 및 데이터 블록

내부 메커니즘 설명시 "데이터"는 데이터, 인덱스, 메타데이터 및 언두 까지 포함함

  • 데이터 변경 4단계
    1. 데이터 블록에 대한 변경을 설명하는 리두 체인지 벡터 생성
    2. 언두 테이블스페이스 내의 언두 블록에 저장될 언두 레코드를 생성 - 원본 데이터를 재 생성하는 방법에 대한 설명을 생성
    3. 언두 블록에 대한 변경을 설명하는 리두 체인지 벡터를 생성 - 원본 데이터를 재 생성하는 방법에 대한 설명을 생성하는 방법에 대한 설명을 생성
    4. 데이터 블록 변경
  • 데이터 변경 단계 변수
    • 오라클 버전
    • 트랜잭션 성격
    • 현재까지 완료된 트랜잭션 일량
    • 데이터 블록 상태
    • 트랜잭션에서 처음 변경 여부

예제

  • OLTP 트랜잭션 수행 중 하나의 Row를 변경하는 예제 (위 4단계의 실제 수행 순서 : 3, 1, 2, 4)
    • 언두/데이터 블록이 변경되기 전에 두 개의 리두 체인지 벡터가 하나의 리두 체인지 레코드로 결합된 후 로그 버퍼에 복사 됨
    1. 언두 레코드를 언두 블록 내에 저장하는 법을 설명하는 리두 체인지 벡터를 생성
    2. 데이터 블록 변경에 대한 리두 체인지 벡터를 생성
    3. 두 개의 리두 체인지 벡터를 하나의 리두 레코드로 결합한 후에 로그 버퍼에 기록
    4. 언두 레코드를 언두 블록에 저장
    5. 데이터 블록을 변경
  • 예제 정보
블록번호저장내용변경레코드
블록#11, 3, 5, 7, 95, 7, 9
블록#22, 4, 6, 8, 106, 8
  • 예제 코드

create table t1
as
select
	2 * rownum - 1			id,
	rownum				n1,
	cast('xxxxxx' as varchar2(10))	v1,
	rpad('0',100,'0')		padding
from
	all_objects
where
	rownum <= 60
union all
select
	2 * rownum			id,
	rownum				n1,
	cast('xxxxxx' as varchar2(10))	v1,
	rpad('0',100,'0')		padding
from
	all_objects
where
	rownum <= 60
;

update
	/*+ index(t1 t1_i1) */
	t1
set
	v1 = 'YYYYYYYYYY'
where
	id between 5 and 9
;

  • 데이터 블록 덤프 결과

-- 업데이트 전
 tab 0, row 4, @0x1d3f
tl: 117 fb: --H-FL-- lb: 0x0  cc: 4
col  0: [ 2]  c1 0a
col  1: [ 2]  c1 06
col  2: [ 6]  78 78 78 78 78 78
col  3: [100]
 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30
 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30
 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30
 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30

-- 업데이트 후
-- Row 길이가 길어져 블록의 프리 영역으로 이동 됨 (@0x1d3f → @0x2a7), 블록 내 레코드 순서 유지 (row 4 / 다섯 번째)
-- 커밋 전 이므로 lock byte 변경 됨(lb:0x0 → 0x2) : ITL 내 두번째 슬롯을 사용하는 트랜잭션에 의해 락이 설정 됨
tab 0, row 4, @0x2a7
tl: 121 fb: --H-FL-- lb: 0x2  cc: 4
col  0: [ 2]  c1 0a
col  1: [ 2]  c1 06
col  2: [10]  59 59 59 59 59 59 59 59 59 59
col  3: [100]
 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30
 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30
 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30
 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30

  • 리두 로그 파일 덤프 결과 (데이터 블록의 리두 체인지 벡터)

CHANGE #2 TYP:0 CLS: 1 AFN:11 DBA:0x02c0018a SCN:0x0000.03ee485a SEQ:  2 OP:11.5
KTB Redo 
op: 0x02  ver: 0x01  
op: C  uba: 0x0080009a.09d4.0f
KDO Op code: URP row dependencies Disabled		<<< Op code: URP(Update Row Piece)
  xtype: XA  bdba: 0x02c0018a  hdba: 0x02c00189		<<< 변경한 블록의 주소 (bdba:), 오브젝트 세그먼트 헤더 블록 주소(hdba:)
itli: 2  ispac: 0  maxfr: 4863		<<< ITL 슬롯 정보
tabn: 0 slot: 4(0x4) flag: 0x2c lock: 2 ckix: 16		<<< 테이블/레코드 정보 (첫번째 테이블, 다섯번째 레코드) ※ Cluster 내 블록 특성 고려
ncol: 4 nnew: 1 size: 4		<<< 컬럼갯수 (ncol:), 변경컬럼수 (nnew:), 크기증감 (size:)
col  2: [10]  59 59 59 59 59 59 59 59 59 59		<<< 컬럼#2 의 변경 후 값

  • 언두 블록 덤프 결과

*-----------------------------
* Rec #0xf  slt: 0x1a  objn: 45810(0x0000b2f2)  objd: 45810  tblspc: 12(0x0000000c)
*       Layer:  11 (Row)   opc: 1   rci 0x0e   
Undo type:  Regular undo   Last buffer split:  No 
Temp Object:  No 
Tablespace Undo:  No 
rdba: 0x00000000
*-----------------------------
KDO undo record:
KTB Redo 
op: 0x02  ver: 0x01  
op: C  uba: 0x0080009a.09d4.0d
KDO Op code: URP row dependencies Disabled		<<<
  xtype: XA  bdba: 0x02c0018a  hdba: 0x02c00189		<<<
itli: 2  ispac: 0  maxfr: 4863		<<<
tabn: 0 slot: 4(0x4) flag: 0x2c lock: 0 ckix: 16		<<<
ncol: 4 nnew: 1 size: -4		<<<
col  2: [ 6]  78 78 78 78 78 78		<<<

  • 리두 로그 파일 덤프 결과 (언두 블록의 리두 체인지 벡터)

CHANGE #1 TYP:0 CLS:36 AFN:2 DBA:0x0080009a SCN:0x0000.03ee485a SEQ:  4 OP:5.1		<<< 적용 해야 할 블록 정보 포함
ktudb redo: siz: 92 spc: 6786 flg: 0x0022 seq: 0x09d4 rec: 0x0f
            xid:  0x000a.01a.0000255b  
ktubu redo: slt: 26 rci: 14 opc: 11.1 objn: 45810 objd: 45810 tsn: 12
Undo type:  Regular undo       Undo type:  Last buffer split:  No 
Tablespace Undo:  No 
             0x00000000
KDO undo record:
KTB Redo 
op: 0x02  ver: 0x01  
op: C  uba: 0x0080009a.09d4.0d
KDO Op code: URP row dependencies Disabled
  xtype: XA  bdba: 0x02c0018a  hdba: 0x02c00189
itli: 2  ispac: 0  maxfr: 4863
tabn: 0 slot: 4(0x4) flag: 0x2c lock: 0 ckix: 16
ncol: 4 nnew: 1 size: -4
col  2: [ 6]  78 78 78 78 78 78

DBMS_UTILITY

SELECT DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILES(TO_NUMBER('0080009a', 'XXXXXXXX')) FILE_NO,
DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(TO_NUMBER('0080009a', 'XXXXXXXX')) FILE_BLOCK
FROM DUAL;

디브리핑

  • 트랜잭션 수행 중에 발생된 변경에 대한 처리 흐름도
  • 진짜 변경 순서
    1. 언두 레코드에 대한 체인지 벡터를 생성한다.
    2. 데이터 블록에 대한 체인지 벡터를 생성한다.
    3. 체인지 벡터들을 하나의 리두 레코드로 결합한 후 로그 버퍼에 기록 한다.
    4. 언두 블록 내에 언두 레코드를 저장한다.
    5. 데이터 블록을 변경한다.
  • 두 개의 체인지 벡터는 하나의 리두 레코드로 결합

REDO RECORD - Thread:1 RBA: 0x00036f.00000005.008c LEN: 0x00f8 VLD: 0x01
SCN: 0x0000.03ee485a SUBSCN:  1 03/13/2011 17:43:01
CHANGE #1 TYP:0 CLS:36 AFN:2 DBA:0x0080009a SCN:0x0000.03ee485a SEQ:  4 OP:5.1
ktudb redo: siz: 92 spc: 6786 flg: 0x0022 seq: 0x09d4 rec: 0x0f
            xid:  0x000a.01a.0000255b  
ktubu redo: slt: 26 rci: 14 opc: 11.1 objn: 45810 objd: 45810 tsn: 12
Undo type:  Regular undo       Undo type:  Last buffer split:  No 
Tablespace Undo:  No 
             0x00000000
KDO undo record:
KTB Redo 
op: 0x02  ver: 0x01  
op: C  uba: 0x0080009a.09d4.0d
KDO Op code: URP row dependencies Disabled
  xtype: XA  bdba: 0x02c0018a  hdba: 0x02c00189
itli: 2  ispac: 0  maxfr: 4863
tabn: 0 slot: 4(0x4) flag: 0x2c lock: 0 ckix: 16
ncol: 4 nnew: 1 size: -4
col  2: [ 6]  78 78 78 78 78 78

CHANGE #2 TYP:0 CLS: 1 AFN:11 DBA:0x02c0018a SCN:0x0000.03ee485a SEQ:  2 OP:11.5
KTB Redo 
op: 0x02  ver: 0x01  
op: C  uba: 0x0080009a.09d4.0f
KDO Op code: URP row dependencies Disabled
  xtype: XA  bdba: 0x02c0018a  hdba: 0x02c00189
itli: 2  ispac: 0  maxfr: 4863
tabn: 0 slot: 4(0x4) flag: 0x2c lock: 2 ckix: 16
ncol: 4 nnew: 1 size: 4
col  2: [10]  59 59 59 59 59 59 59 59 59 59

Private redo & in-memory undo

  • Oracle 10g 리두 체인지 벡터에 중요한 변경 사항 발생
  • RAC 적용 불가, 변경 량이 많거나 Supplemental 로깅, Flashback Database 활성 시 이전 방식으로 동작

트랜잭션 요구사항 (ACID)

  • ACID 요구 사항
    • 원자성(Atomicity) - 데이터 변경은 All or Nothing
      • 수행중인 트랜잭션을 커밋하기 전까지 다른 트랜잭션에서 확인할 수 없으며 언두 레코드를 통해 커밋 전 데이터를 제공 한다.
    • 일관성(Consistency) - 일관된 데이터베이스 상태 유지
      • 사용자는 다른 트랜잭션에 의해 데이터가 변경중인 상태를 볼 수 없다, 트랜잭션 수행 전/후 각각의 상태만 제공 받는다.
    • 격리성(Isolation) - 다른 트랜잭션에 끼어들 수 없다
      • 언두 레코드는 트랜잭션 수행 중 다른 트랜잭션에 의해 영향 받는 내용을 확일할 필요가 없도록 한다.
    • 내구성(Durability) - 커밋된 트랜잭션은 반드시 복구
      • 리두 로그가 존재하지 않는다면, 변경사항이 발생하는 수 많은 데이터 블록들을 별도 저장 필요
  • 격리성 레벨
    • read committed (기본값)
    • read only
    • serializable
  • 격리성 레벨 데모
SessionSQLread committedread onlyserializable
1SELECT * FROM T1;1 rows selected1 rows selected1 rows selected
2INSERT INTO T1 SELECT * FROM T1;
2COMMIT;
1SELECT * FROM T1;2 rows selected1 rows selected1 rows selected
1INSERT INTO T2 SELECT * FROM T1;2 rows createdORA-014561 rows created
  • 언두와 리두를 위한 메커니즘은 ACID 의 기본적인 요구사항 구현에 충분하고, 성능/복구 측면의 장점도 있다.
    • 성능
      • 내구성 : 리두 로그가 없다면?
      • 격리성 : 장시간 리포트 작업시 언두 메커니즘으로 고수준의 동시성 레벨 제공 (언두가 없다면 잘못된 결과를 보거나 락을 대기)
    • 복구
      • 백업된 데이터 파일을 Restore 한 후 현재까지 변경사항을 재 적용하여 복구 시간 단축 한다. (리두)

리두 단순성

  • 리두 처리 방식
    1. 리두 레코드의 연속된 스트림을 지속적으로 생산
    2. 로그 버퍼(공유메모리) 영역에 기록
    3. 가능한 빨리 온라인 리두 로그 파일에 저장 (Round-Robin 재사용)
    4. 다쓴 온라인 리두 로그 파일은 Archived 리두 로그 파일로 복사 (장기 보관 목적)

write and forget

리두 로그 파일에 기록된 내용은 일반 적인 상황에서 다시 읽혀지지 않으므로 신경 쓸 필요가 없다.
이러한 "write and forget" 접근 방식은 리두를 매우 단순하게 처리할 수 있도록 한다.
&#x203b; 버퍼 캐시 내 버퍼가 손상 되면 디스크의 블록과 리두 로그를 이용하여 복구 한다.

  • 병목 현상 - 로그 버퍼를 접근하기 위한 경합
    • 오라클 10g 이전 까지는 하나의 로그 버퍼에 다수의 세션들의 변경사항에 대한 리두 레코드를 매번 기록함.
    • 로그 버퍼 공간할당 필요시 redo allocation 래치를 exclusive 모드로 획득 필요 (로그 버퍼 보호)
      • 다수 프로세스의 지속적인 래치 경쟁 시 많은 리소스를 소비(spinning) 하거나 긴 슬립 타임 발생
  • 병목 개선 - 10g 의 private redo 와 in-memory undo 메커니즘
    • 트랜잭션 당 한번만 public redo allocation 래치 획득
    • 트랜잭션 수행 중 생성된 체인지 벡터는 private redo 로그 버퍼에 저장, 트랜잭션 완료시 모두 public 로그 버퍼로 복사

log_parallelism

  • Oracle 9.2 에서는 log_parallelism 파라미터로 multiple 로그 버퍼 제공 (CPU 16개 이상)
  • Oracle 10g 에서는 CPU 개수가 1개 이상만 되면 적어도 두 개의 public 로그 버퍼가 생성 됨
  • 병목 개선 데모 - 50 rows updated

9.2.0.8
=======
Latch                              Gets      Misses     Sp_Get     Sleeps     Im_Gets   Im_Miss Holding Woken Time ms
-----                              ----      ------     ------     ------     -------   ------- ------- ----- -------
redo copy                             0           0          0          0          51         0       0     0      .0
redo allocation                      53           0          0          0           0         0       0     0      .0

redo writing                          3           0          0          0           0         0       0     0      .0
undo global data                      3           0          0          0           0         0       0     0      .0
cache buffers chains                267           0          0          0           1         0       0     0      .0

Name                                                                     Value
----                                                                     -----
redo synch writes                                                            1
redo entries                                                                51
redo size                                                               12,668
redo wastage                                                               228
redo writes                                                                  1
redo blocks written                                                         26

10.2.0.3
========
Latch                              Gets      Misses     Sp_Get     Sleeps     Im_Gets   Im_Miss Holding Woken Time ms
-----                              ----      ------     ------     ------     -------   ------- ------- ----- -------
redo writing                          3           0          0          0           0         0       0     0      .0
redo copy                             0           0          0          0           1         0       0     0      .0	<<< 급감
redo allocation                       5           0          0          0           1         0       0     0      .0	<<< 급감
undo global data                      5           0          0          0           0         0       0     0      .0
In memory undo latch                 53           0          0          0           1         0       0     0      .0	<<< 급증(신규)
cache buffers chains                379           0          0          0           0         0       0     0      .0

Name                                                                     Value
----                                                                     -----
redo synch writes                                                            1
redo synch time                                                              1
redo entries                                                                 1	<<< 급감
redo size                                                               12,048	<<< 감소
redo wastage                                                               352

redo writes                                                                  1
redo blocks written                                                         25

undo change vector size                                                  4,632
IMU commits                                                                  1
IMU undo allocation size                                                43,052

  • Oracle 10g 의 새로운 메커니즘
    • x$kcrfstrand - private redo / 데이터 블록에 대한 체인지 벡터
      • 조회 시 두개의 패턴이 보임 (public, private)

SQL> select indx, first_buf_kcrfa, strand_size_kcrfa from x$kcrfstrand;

      INDX FIRST_BUF_KCRFA  STRAND_SIZE_KCRFA
---------- ---------------- -----------------
         0 070000000021E000           3694592	<<< public
         1 07000000005A4000           3694592	<<< public
         2 070000005244A000            132096	<<< private
         3 070000005246B000            132096
         4 070000005248D000            132096
...
       175 0700000051B53000            132096
       176 0700000051B74000            132096
       177 0700000051B95000            132096

178 rows selected.

      • public 로그 버퍼 개수 = ceiling ( 1 + cpu_count / 16 )
      • 각 항목은 각각의 redo allocation 래치로 관리
      • public 로그 버퍼는 CPU 당 하나의 redo copy 래치로 관리
    • x$ktifp - in-memory undo pool / 언두 체인지 벡터
      • 구조 내 pool 개수 = transactions / 10
      • In memory undo latch 래치로 관리
  • Oracle 10g 의 새로운 메커니즘 데모
    1. Private 메모리 구조 (x$ktifp, x$kcrfstrand) 내 연관된 엔트리들을 획득 (트랜잭션 시작)
    2. 트랜잭션에 영향받는 블록에 "has private redo" 플래그 설정
    3. in-memory undo pool 에 각 언두 체인지 벡터 기록
    4. private 로그 버퍼에 각 리두 체인지 벡터 기록
    5. 두개 구조에 저장된 체인지 벡터를 하나의 리두 체인지 레코드로 결합 (트랜잭션 종료)
    6. 리두 로그에 리두 체인지 레코드를 복사하고 블록에 변경사항을 적용
  • 5 개 로우 변경 트랜잭션 커밋 전 메모리 구조 (private)

INDX  UNDO_SIZE UNDO_USAGE  REDO_SIZE REDO_USAGE
----- --------- ----------- --------- ----------
    0     64000        4352     62976       3920

-- 하나의 세션에 할당될 수 있는 메모리는 약 64KB, 사용은 약 4KB

  • 5 개 로우 변경 트랜잭션 커밋 후 리두 로그 파일 덤프 결과
  • OP: 코드
    • 5.2 : 트랜잭션 시작 (CHANGE #2) - undo segment header block 에 적용
    • 11.5 : 데이터 체인지 벡터
    • 5.4 : 트랜잭션 종료 (CHANGE #7) - commit record
    • 5.1 : 언두 블록 체인지 벡터
  • 모든 변경은 In memory undo latch 를 액세스 함
    • 기존에 두 개의 래치(redo allocation, redo copy) 대신 하나의 래치(In memory undo)만 획득 - 래치 활동성 감소
    • In memory undo pool 당 하나의 In memory undo 래치가 할당 됨 - 래치 분산
  • 두가지 유형의 redo allocation 래치 존재
    • private 로그 버퍼 : 로그 버퍼 획득을 위해 private redo allocation 래치 사용
    • public 로그 버퍼 : LGWR가 로그 버퍼 내용을 파일에 기록 할때 public redo allocation 래치 사용

최적화를 위한 중요한 원칙

동일한 경합 위치에서 끊임없이 충돌하는 것 보다는, 분리된 위치에서 약간 더 일하는 것이 전체 사용자를 위해 더 좋은 방법

  • 단점
    • 이전 메커니즘 보다 로그 버퍼 및 데이터베이스 블록에 반영해야 할 양이 상대적으로 크다. → 시간이 더 걸린다 → 다른 세션을 블로킹 한다 → private 로그 버퍼 크기를 엄격히 제한
    • 변경된 블록을 읽는 두 번째 세션은 private 리두를 적용한 블록만을 볼 수 있으므로, 두 번째 세션은 private 리두를 찾아내고, 블록에 적용할 책임이 있다. (복잡하다)
      • 이전 메커니즘은 두 번째 세션은 변경사항을 즉시 볼 수 있다.
  • 세션이 새로운 메커니즘 사용 못할 때
    • private 로그 버퍼 혹은 in-memory undo pool 이 풀방 일때 (64KB or 128KB) 이전 방식으로 동작

SQL> select ktiffcat, ktiffflc from x$ktiff;

KTIFFCAT                                   KTIFFFLC
---------------------------------------- ----------
Undo pool overflow flushes                      632
Stack cv flushes                              73642
Multi-block undo flushes                          0
Max. chgs flushes                              2197
NTP flushes                                       0
Contention flushes                             1208
Redo pool overflow flushes                        0
Logfile space flushes                             0
Multiple persistent buffer flushes                0
Bind time flushes                                 0
Rollback flushes                              25099
Commit flushes                               292164
Recursive txn flushes                           700
Redo only CR flushes                             61
Ditributed txn flushes                            0
Set txn use rbs flushes                           0
Bitmap state change flushes                  112760
Presumed commit violation                         0
Securefile direct-write lob update flush          0
es


19 rows selected.


언두 복잡성

  • 모든 프로세스는 언제든 커밋 전 데이터(언두 레코드)를 확인 할 수 있어야 한다.
    • 프로그램은 언두 레코드를 쉽게 찾기 위해 다양한 포인터를 유지 한다.
    • 언두 레코드는 언두 테이블스페이스에 저장되고, 다른 블록들과 동일한 기록, 버퍼링 및 복구 알고리즘을 가진다.
  • 언두 레코드 목적
    1. 읽기 일관성
    2. 롤백
    3. delayed block cleanout 으로 잃어버린 commit SCN 유추

읽기 일관성

  • 블록은 변경 전 내용을 확인할 수 있는 언두 레코드에 대한 제한된 개수의 포인터를 ITL 엔트리 내 저장한다.
  • 언두 레코드를 생성하면, 기존의 포인터 중의 하나를 덮어쓰며, 이전 값을 언두 레코드 내의 한 부분에 저장한다.
  • 언두 레코드

*-----------------------------
* Rec #0xf  slt: 0x1a  objn: 45810(0x0000b2f2)  objd: 45810  tblspc: 12(0x0000000c)		<<< 언두 블록 내의 0xf 에 기록
*       Layer:  11 (Row)   opc: 1   rci 0x0e		<<< 참고
Undo type:  Regular undo   Last buffer split:  No 
Temp Object:  No 
Tablespace Undo:  No 
rdba: 0x00000000
*-----------------------------
KDO undo record:
KTB Redo 
op: 0x02  ver: 0x01  
op: C  uba: 0x0080009a.09d4.0d		<<< op: C 동일한 트랜잭션에 의해 이전에 변경된 것이 존재
KDO Op code: URP row dependencies Disabled
  xtype: XA  bdba: 0x02c0018a  hdba: 0x02c00189
itli: 2  ispac: 0  maxfr: 4863
tabn: 0 slot: 4(0x4) flag: 0x2c lock: 0 ckix: 16
ncol: 4 nnew: 1 size: -4
col  2: [ 6]  78 78 78 78 78 78

-- uba: 0x0080009a.09d4.0d 해당 블록의 이전 버전 재 생성시 사용 정보
-- 이전 버전 재생성 : "xxxxxx" 는 로우4, 컬럼2 로 다시 복사, 0x0080009a.09d4.0d 는 ITL 엔트리 2로 다시 복사

  • 이전 버전 재생성 단계는 점차적으로 시간을 거슬러 올라갈 수 있다.
    • 각 ITL 엔트리 내의 포인터는 적용해야 할 언두 레코드를 찾을 수 있는 위치를 알려 준다.
    • 언두 레코드는 데이터뿐 아니라 ITL 엔트리 과거 시점 정보를 포함 한다.

롤백

  • 롤백
    • 명시적 rollback (rollback to savepoint)
    • 트랜잭션 실패에 의한 명령어 레벨의 롤백
구분읽기 읽관성롤백
특징싱글 블록에 대한 모든 언두 레코드의 링크드 리스트 검색트랜잭션의 이력, 정확한 순서로 트랜잭션에 대한 모든 언두 레코드의 링크드 리스트 검색
차이점메모리 내 데이터 블록 복사본 생성 후 언두 레코드 적용, 사용 후 빠른 폐기 가능current 블록 획득 후 언두 레코드 적용

언두 레코드의 backward 순 적용

1. 하나의 로우를 두 번 변경 (A → B → C)
2. 두개의 언두 레코드 생성
3. 원복시 B → A 전에 C → B 먼저 적용 필요 (두 번째 언두 레코드를 먼저 적용)

  • rci 0x0e : 같은 블록 내 직전 언두 레코드 (Rec #0xf : 현재 언두 레코드)
    • 다른 블록 내 직전 언두 레코드 케이스 : current 언두 레코드가 언두 블록의 첫 번째 언두 레코드인 경우 (rci : 0, rdba : 이전 언두 레코드의 블록 주소 제공)
    • 블록의 이전 버전 생성 : irb: 항목이 가리키는 마지막 언두 레코드 필요 (rollback to savepoint 수행 시 irb: 가 마지막 언두 레코드가 아닐 수 있음)
  • 롤백의 특징
    • 해당 current 블록은 반드시 디스크로 기록 된다
    • current 블록 이므로 과거 시점으로 포함 변경시 리두 생성 됨
    • crash-recovery 메커니즘에 의해 사용된 언두 레코드는 "Undo Applied" 로 표시 된다 (롤백에 사용되면 User Undo Applied" 표시 됨 : 1 BYTE)
    • 원본 트랜잭션과 거의 동일한 수행 시간 과 리두 생산 필요
    • 데이터 블록을 변경하는 활동, 디스크에 기록된 블록을 버퍼 캐시로 읽어 들임, 변경에 대한 리두 발생
    • 오버헤드
      • 언두 생성 시 : 언두 블록 획득, pin 설정, 한번에 하나의 언두 블록 채우기
      • 롤백 시 : 한번에 하나의 언두 레코드 획득하고 레코드에 대한 블록을 릴리즈하고 재 획득 (더 많은 버퍼 액세스, 매 언두 레코드 획득 시 언두 테이블스페이스 온라인 여부 점검)
        {tip:title=global temporary table}
        임시 정보 저장 및 private 한 읽기 일관성 구현을 위한 일반 테이블 + rollback 구성은 비싸서(롤백) 안좋다.
        {tip}

요약

  • 블록 변경은 redo change vector 에 의해 설명 되고, 즉시 로그 버퍼 및 로그 파일에 기록 됨
  • 데이터 변경시 원복 방법(언두 레코드)이 언두 테이블스페이스 내 생성 됨
  • 10g 전까지 한쌍(데이터 블록 체인지 벡터, 언두 레코드 체인지 벡터)으로 구성된 리두 레코드를 로그 버퍼에 기록
  • 10g 부터 제한된 크기의 private 영역 내에 트랜잭션에 대한 변경을 보관 (꽉 차면 이전 메커니즘으로 전환)
  • 리두 는 "write it and forget it", 언두는 효율적 엑세스를 위한 다양한 방법의 링크 존재
  • 읽기 일관성은 블록에 대한 언두 레코드 체인, 롤백은 트랜잭션에 대한 언두 레코드의 체인 필요