07 Consistent vs Current 모드 읽기
07 대제목에 나와있듯, 블록 읽기 모드에도 여러가지 모드가 있음.
- Consistent mode
- ‘쿼리를 떄린 그 시점의 SCN값을 기준으로 값을 읽음’
- Current mode
- ‘쿼리를 떄리고 나서, 데이터를 찾아간 바로 그 시점의 최종 값을 읽음’
근데… 앞선 SCN이 어쩌고저쩌고 하는걸 보면… 단순이 SELECT하는 쿼리문은 Consistent모드로 읽지 않나?
그렇지 않음… DML을 할 때에도 “UPDATE SET A = A+1” 과 같이 이전 값을 읽어야 할 시점이 있을거고, SELECT FOR UPDATE문과 같이 UPDATE 직전에 데이터를 읽는 경우도 있음. 이때 바로 오라클은 Current mode를 통해 데이터를 읽는다고 한다.
자세한 내용은 모르겠고… 그저 ‘일반적인 단순 SELECT는 Consistent mode로 데이터를 읽지만, 다음과 같은 예외 케이스에 Current mode로 데이터를 읽는 경우도 있다’ 정도를 외워두자.
- DML
- SELECT FOR UPDATE
- 디스크 소트가 필요할 정도로, 대량의 데이터를 정렬할 때
- 등등등등….
책에서 갑자기 별로 필요할 것 같지도 않은 Current mode에 대해서 너줄너줄 설명을 하기 시작한다..하지만 Current mode가 필요한 경우가 분명 존재한다.
1) Consistent 모드로만 읽는 경우

7788사원의 초기 sal 이 1000인 경우에, TX1,TX2를 다 수행한 다음의 최종 결과값은 뭐가 나와야 하남…
- 1장 6까지 공부해 본 학문적인 관점에서 접근해 보자. –> Consistent 모드
- TX2시점에서 읽어온 sal값이 1,000으로 읽어야 하니, 1200원이 되어야 할 것이네.
하지만 난 (개나소나 하는거지만) 무려 커머스 서비스 개발자다…..
저게…맞아?
- Current 모드적인 관점에서 생각해 보자.
- TX1시점에서 업데이트 되는 값도, 사실 엄연히 정상적인 서비스 쿼리임.
- 7788사원의 최종 sal값이 1,300이어야 아무래도 문제가 안 생기지 않겠음…?
Consistent모드의 관점에서 발생하는 저 문제상황을 ‘Lost Update’ 케이스라고 칭하고, 이 문제를 회피하려면, 갱신 작업은 Current 모드로 읽어야 한다.
그렇구나….
그럼 다음현상.
2) Current 모드로만 읽는 경우

7788 사원의 최종적인 sal 값은 어떤 값이 나와야 하남….
- 2000이 나와야 맞나? 3000이 나와야 맞나?
일단 Current 모드로 읽는 경우를 따져봤을 땐, TX2가 읽는 시점이 7788사원의 sal이 2000으로 찍혀있기에 최종적으로 3000이 나오게 된다.
그럼 이 경우는…?

t테이블의 no가 1~100,000까지 있다고 했을 떄, TX1과 TX2가 상황 3과 같은 트랜잭션 상황에서 업데이트가 이루어 지면, 최종적으로 TX1이 업데이트 친 row count는 5만건이어야 할까? 5만+1건이어야 할까?
- 실제로 SQL Server에서 수행하면 5만+1건이 수행된다고 한다. –> Current모드로 갱신을 한다는 뜻.
Consistent 모드로 읽고, Current 모드로 갱신할때 생기는 현상
Current 모드로 갱신을 수행할 때에도 일관성이 없는 모습의 예시가 존재한다.
그래서 오라클은, Consistent모드로 읽고 & Current모드로 갱신을 수행한다. –> 뒤에 나오겠지만 단순히 ‘Consistent모드로 읽는’ 것이 아니라, ‘ Consistent모드로 갱신대상을 식별한다’ 라는 표현이 적절하겠다.


sal의 초기값이 1,000이라 할 때, 이와 같은 상황에서의 7788사원의 sal값은 어떻게 되는걸까?
1,100? 1,300?
Consistent모드로 읽고 Current모드로 갱신한다면, 1,300이라는 값이 나와야 하는 것이 옳겠으나…. 그럼 결국 ‘이미 1,100으로 업데이트 된 값을 재생긴 하는’ 신뢰성 없는 동작을 하는 결과를 낳게된다.
하지만 오라클에서도 TX2의 갱신은 실패한다고 한다.
Consistent모드로 갱신대상을 식별하고, Currrent모드로 갱신

수도코드로 표현하면 위의 그림처럼 수행이 되는데, 이걸 단계 1/2로 나누어서 보면 다음과 같다.
- Consistent모드로 일단 갱신할 레코드를 읽는다.
- 1단계에서 읽은 rowid를 찾아가 low lock을 설정한 다음데, Current모드로 갱신을 수행한다. 이때, 1단계에서 읽은 where조건을 신뢰하지 않고, 최종 갱신 직전에 Current모드로 다시 한번 조건을 체크하고 갱신을 한다.
라고 한다.
1단계에서 갱신할 레코드를 읽는다고 해서, ‘이 친구들을 모두 다 업데이트 할거야’ 하는게 아니라, ‘실 업데이트 직전에 또 한번 체크를 한다’ 라는 개념으로 동작한다.
- 그럼 단계 1은 왜 필요한데?
갱신이 진행되는 타이밍에, “제 3의 트랜잭션이 7788사원의 sal을 1,000으로 변경하는 동작이 추가로 진행될 수도 있어서” 임.
갱신이 진행되는 동안 추가/변경을 통해 “새롭게 범위 안에 들어와버리는 레코드를 제외하기 위함” 이라고 표현해도 되고.
아무튼 그리하여, 오라클은 상기의 상황에서도 TX2에서 일관성을 보장하지 못하는 갱신을 ‘Consistent모드로 갱신대상 식별 && Current모드로 갱신’ 하는 방법을 통해 일관성 보장을 해 준다.
그럼에도 불구하고 일관성 없게 값을 갱신하는 사례
| 7788사원의 ‘계좌1’ 테이블의 데이터 | 7788사원의 ‘계좌2’ 테이블의 데이터 |
| 잔고 : 1,000 | 잔고 : 1,000 총잔고 : 2,000 (계좌1 + 계좌2 의 총 잔고를 저장하는 컬럼) |
요때 다음과 같은 동작을 수행하면 이런 문제가 발생한다.
TX1> UPDATE 계좌1 set 잔고=잔고+100 WHERE 7788;
TX2> UPDATE 계좌2 set 잔고=잔고+200 WHERE 7788;
두개의 트랜잭션이 동시에 수행될 때, 원하는 계좌2의 ‘총잔고’ 컬럼은 2,300이 되어야 하는데, 2,200으로 찍힌다고 한다.
계좌2에서 잔고를 읽을땐 Current모드에서 읽지만, 계좌1에서 잔고를 읽을땐 Consistent모드로 읽기 때문이라고 한다.
그래서 이런 경우에 올바르게 값 일관성을 보장하려면 TX2에 쿼리를 이런 식으로 변경하면 된다.
TX2> UPDATE 계좌2 set 총잔고 = (SELECT 잔고+ 계좌2.잔고 FROM 계좌1 WHERE 계좌 = 계좌2.계좌번호)
WHERE 7788;
이떄 계좌1,2 잔고를 모두 Current모드로 읽기 떄문에, TX2의 쿼리를 2,300으로 찍는다고 한다.
(어…..보통은 이러면 그냥 트랜잭션이 안겹치게 시간차를 두고 배치를 수행하거나 할 것 같긴 하다… 불확실성이 너무 큼…)
08 블록 클린아웃
간단하다… 대량 DML이후 커밋 시, 커밋 완료를 각 블록을 찾아다니며 블록 클린아웃을 수행하는건 너무 오래 걸리기에, 성능 최적화를 위한 기법을 설명해 주고 있다
Delayed 블록 클린아웃
버퍼캐시 블록 개수의 10% 이상을, 트랜잭션이 갱신한 블록 개수가 차지할때 딜레이 블록 클린아웃을 진행한다.
딜레이 시점 : 커밋 이후, 해당 블록이 최초로 read되는 시점에 클린아웃.
커밋 클린아웃
오라클이 그렇다고 최적화된 클린아웃 방식을 Delayed 블록 클린아웃만 쓰면, 대량 SELECT때 또 문제가 발생할 수 있다.
책에서는 RAC OPS의 예시를 들어 이야기 하는데… 사실 이해가 잘 가지 않아서 그냥 패스.. (별로 중요하지 않은 것 같기도 하고)
OPS환경에서 인스턴스간에 블록을 주고받는 과정인 ‘핑’이란걸 하는데, 이 ‘핑’이 과도하게 발생하는걸 막아주는 역할을 한다고 한다.
ITL과 블록 클린아웃
…..