본문 바로가기

분류없는 게시글

DBMS의 심장 트랜젝션과 동시성 제어

DBMS의 심장 트랜젝션과 동시성 제어

이상원 swlee@acm.org

21세기의 IT분야는 매 일같이 신기술, 새 로운 용어, 생소한 개념이 등장하 기 때문에 이 분야 종사자들은 새 로운 용어를 듣고 따라가기에도 정신이 없을 정도다.
공들여서 새 로운 것을 배울라치면 채 1년도 못돼 쓸모 없지나 않을까 걱정이 앞서게 된다. 이런 와중에도 앞으 로 10년이 지나도 여전히 중요하 면서 깊이 있게
알면 알수록 더 재미있는 기술이 없을까? 트랜잭 션 처리 기술은 관계형 데이터 모 델, 옵티마이저 기술과 더불어 관 계형 DBMS 성공의 가장 핵심 기술이다.
그러나 이 기술은 많은 사람들이 제대로 이해하고 있지 못하고, 또한 초보자나 중급자가 그 개념을 쉽게 이해하기가 어렵 다. 또한 특정 DBMS의 트랜잭 션과
동시성 제어(Concurrency Control) 기술에 대해 쉽게 정리 된 글이 없는 관계로, 본 지면을 빌려서 초보자나 중급자가 쉽게 이해할 수 있도록 기본 원리를 중
심으로 정리해 보고자 한다. 오라 클 데이터베이스를 중심으로 설 명할텐데, 이 기본 원리 자체는 아마 10년이 지나도 크게 바뀌지 않을 것이다.

 

관계형 DBMS와 트랜적션 기능

관계형 데이터베이스와 관련해서 가장 중요한 기술 세 가지를 꼽으라면 필자는 주저 없이 . 관계형 데이터 모델, . 질의 최적 화 기술, . 트랜잭션 처리 기술을 들
것이다. 우선 관계형 데 이터 모델(참고자료 .)은 일반 사용자들이 데이터를 2차원 의 테이블과 간단한 SQL문으로 원하는 데이터를 손쉽게 다 루는 것을
가능하게(데이터 처리 업무의 생산성을 높였다) 했 다는 측면에서 의의가 있다. 이 관계형 데이터 모델을 처음 제 안한 E. F. Codd 박사는 이 공로로 컴퓨터
분야의 노벨상에 해당하는 튜링상을 1980년에 수상했다. 둘째, 본지 2002 8 월호에서 살펴본 것처럼 관계형 데이터 모델에 기반한 DBMS가 성능 측면에서
실용적으로 사용될 수 있는 이유는 관계형 DBMS의 두뇌 역할을 하는 옵티마이저(optimizer, 질의 최적화기)가 있기 때문이다. 마지막으로, 관계형 DBMS
에서 파일 시스템과는 달리 트랜잭션 개념을 직접 지원하고 동시에 수많은 사람이 공유 데이터를 접근해 사용해도 문제가 없는 것은 효과적인 트랜잭션 처리
기술(참고자료 .)을 갖고 있기 때문이다. 모든 관계형 DBMS는 트랜잭션 처리를 담당 하는 트랜잭션 관리자를 포함하고 있다. 관계형 DBMS의 트 랜잭션 처리
기술 선구자 중의 한 사람인 짐 그레이(Jim Gray) 박사도 이 분야에 대한 공헌으로 1998년도에 튜링상을 수상했다.

 

트랜잭션의 개념

비즈니스적 측면 데이터베이스는 실제 비즈니스에서 발생하는 정보들을 저장 하고 관리한다. 그렇다면 비즈니스에서 트랜잭션은 무엇인 가? 학교에서 수강신청,
은행 계좌이체, 온라인 쇼핑몰에서 구매 등이 모두 트랜잭션에 해당한다. 이와 같은 실제 비즈니 스 상에서 일어나는 트랜잭션 관련 데이터를 저장하고 기록하 는
것이 데이터베이스의 역할이다. 이제 비즈니스 트랜잭션의 특징에 대해 좀더 자세히 알아보 자. 예를 들어, 계좌이체의 경우 A라는 구좌에서 B구좌로 50 만원을
이체한다고 하자(A 구좌는 100만원 이상 예금되어 있 다고 가정). 이 계좌이체는 다음과 같이 두 가지 중요한 일을 수행한다.

. A 구좌에서 50만원을 빼고,

. B 구좌에 50만원을 더한다.

이 계좌이체 트랜잭션 과정은 50만원이 성공적으로 A 구좌 에서 B 구좌로 이동하든지, 아니면 아예 계좌이체가 일어나 지 않은 상태로 되어야 한다. 즉 트랜잭션을
이루는 두 가지일이 모두 성공적으로 발생하든지, 또는 하나도 발생하지 않 아야(all-or-nothing) 정상이다. 다시 말해 은행도 개인도 손 해를 보지 않아야 한다.
만일 A 구좌 고객이 ATM 단말기에 서 계좌이체를 수행하다 문제가 발생해서 첫 번째 일만 수행 하고, 두 번째 일을 수행하지 못했다면 은행만 50만원을 벌게
되는 결과가 된다. 따라서 트랜잭션은하나의 정상적인 상태 (이 예의 경우 A, B 두 구좌 모두 정확한 잔고가 남아 있는 상 태)에서 또 다른 정상적인 상태(A-50, B+50)
전이하는 논 리적인 일의 단위(a logical unit of works)이다. 논리적으로 정상적인 상태에서 다른 정상적인 상태로 바꾸는 논리적인 일 의 단위가 바로 비즈니스
측면에서의 트랜잭션을 의미한다.

 

기술적인 측면

실제 비즈니스 트랜잭션의 전후 데이터 값을 저장/관리하는 것이 데이터베이스의 역할이다. 그렇다면 이와 같은 비즈니스 트랜잭션을 제대로 지원하기 위해 S/W
기술적인 측면에서 트랜잭션 기술은 어떤 특징을 가져야 할 것인가? 이를 위해 기술적으로 데이터베이스의 트랜잭션 기능은 다음과 같은 네 가지의 중요한 성질을
제공할 수 있어야 한다. 이 네 가지 성 질을 줄여서(기술적인 측면에서) 트랜잭션이 만족해야 할 ACID 속성이라고 한다.

원자성(Atomicity) :
이 성질은 비즈니스 측면에서 트랜잭션의‘all-ornothing" 성질을 기술적으로 보장하기 위해 필요하다. 즉 데이터베이스 값은 하나의 트랜잭션을 이루는 개별 작업들이
모두 다 성공적으로 끝나든 지, 아니면 하나도 발생하지 않은 상태로 복원돼야 한다. 앞의 계좌이체를 예로 들면, 데이터베이스는 어떤 경우든지 A 구좌에서 100만원이
빠지고, B에는 변동이 없는 경우는 없어야 한다. 만일 계좌이체 중간에 데이터베 이스 시스템의 전원이 나가는 경우에도 다시 복구(recovery)를 수행하면, 데이터베이스
내의 A 구좌와 B 구좌는 해당 트랜잭션이 발생하기 전의 상 태로 돌려져 있어야 한다.

일관성(Consistency) :
이 성질은 비즈니스 측면의 트랜잭션 개념이 데이 터베이스를 하나의 정상적인 상태에서 또 다른 정상적인 상태로 바꾸는 것 과 관계가 있다. 기술적인 측면에서
트랜잭션의 일관성에 대한 책임은 비 즈니스 측면의 계좌이체를 정확히 응용 프로그램으로 구현하는 프로그래 머에게 있다. 예를 들어, 계좌이체의 경우 트랜잭션
수행 전의 A, B 구좌 의 잔액의 합이 수행 후에도 동일하도록 프로그램을 작성해야 한다.

지속성(Durability) :
이 성질은 일단 트랜잭션의 처리가 정상적으로 끝나 고 나면, 이후에 시스템 오류가 발생하는 경우에도 해당 트랜잭션의 결과 가 데이터베이스에 보장돼야 한다는
것이다. 예를 들어, 계좌이체의 경우 ATM 단말기에서 A가 성공적으로 계좌이체가 끝났다는 전표를 받아든 이후에, 비록 데이터베이스 시스템의 전원이 나가는
경우에라도 반드시 복구 해서 계좌이체가 끝난 후의 상태를 보장해야 한다는 것이다.

동시성 접근에 따른 이상 현상

독립성(Isolation) :
데이터베이스는 기본적으로 여러 사용자가 동시에 데 이터를 접근해서 사용할 수 있다. 각 트랜잭션에 대해 기술적으로 원자성, 일관성 그리고 지속성이 보장된다
하더라도, 이러한 동시 사용 (concurrent access)으로 인해 여러 사용자가 동시에 같은 데이터를 접 근하면 예기치 않은 결과가 나올 수 있다. 예를 들어, A구좌에서
B
구좌로 의 계좌이체 트랜잭션 T1의 중간에(좀더 정확히는 A 구좌에서는 50만원 이 빠져나가고, B 50만원을 더하기 전에), 다른 트랜잭션 T2가 은행 전 체
구좌의 잔고 합을 구하기 위해 A 구좌와 B 구좌의 잔고 값을 읽는다면, T2 50만원이 부족한 결과를 얻게 된다. 이는 T2 T1의 중간 상태의 값을 읽었기 때문에
나타나는 현상이다. 그렇다면 T2가 정상적인 결과 값 을 구하기 위해 기술적으로 데이터베이스에서 보장해야 할 일은 무엇인 가? T2 T1의 시작 전 상태의 A, B
구좌 값을 읽거나, T1이 종료된 후 의 A, B 구좌 값을 읽도록 해야 한다. 마치 T2-T1 또는 T1-T2의 순서로 트랜잭션이 동시가 아니라 순차적으로 수행된 것처럼
데이터베이스 상태 를 보장해야 한다. 네 가지 트랜잭션의 기술적인 성질을 보장하기 위해 상용 관계형 DBMS들은 트랜잭션 관리자 모듈을 포함하고 있다. 트랜잭션
관리자는 크게 동시성 제어 모듈과 회복 모듈을 갖 고 있다. 동시성 제어 모듈은 같은 데이터에 대한 동시 접근으 로 인해 발생할 수 있는 문제를 방지하기 위한 모듈
(다시 말 해, 주로 독립성을 보장)이고, 회복 모듈은 시스템의 오류로 부터 원자성과 지속성을 보장하는 역할을 한다. < 1>은 지 금까지 설명한 내용을 정리한 것이다.
이 글에서는 네 가지 기술적인 성질 중에서 동시 접근에 따른 독립성 보장과 관련한 다양한 문제들 을 기본 동작 원리를 중심으로 알아보겠다. 기술적 으로 회복 모듈은
이 글의 범위를 벗어나기 때문에 깊이있게 다루지는 않겠다.

 

동시 접근에 따른 문제점

여러 트랜잭션이 공유 데이터를 동시에 접근하는 경우, 만일 동시성 제어 기능이 없다면 일반적으로 네 가지의 이상 현상(anomaly)이 발생한다. 이들 각각에 대해
간단히 알아보자.

◆ DW(Dirty Writes) :
트랜잭션 T1 A 계좌에서 잔액으로 120만원을 지정하고, 거의 동시에 T2 A 계좌 잔액을 150 만원으로 바꿀 때, T1이 다시 A 계좌의 값을 읽으면 120만 원을
읽는 게 정상이다. 하지만 여기서는 T2에 의해 값이 바 뀌었기 때문에 150만원으로 읽게 된다. 같은 데이터에 대해 동시에 두 개 이상의 트랜잭션이 값을 바꾸고자
할 때 발생하 는 문제를 DW라고 한다(<그림 1-.> 참조).

◆ DR(Dirty Reads) :
앞서 예로 든 계좌이체 트랜잭션 T1의 수행과 동시 에, 트랜잭션 T2에서 전체 고객의 계좌 잔액을 구하는 질의를 수행한다고 가정하자. <그림 1-.>에서는 T1에서
A
의 값을 바꿔 기록한 바로 직후에 T2에서 A, B 계좌의 값을 읽었다면, 논리적으로 비정상적인 결과를 얻게 된다. 좀더 기술적으로 말하면, T2는 아직 종료(commit)
되지 않은 트랜 잭션 T1의 쓰기 내용을 읽은 것이다. dirty read를 수행하게 된 것이다 (<그림 1-.> 참조).

◆ NRR(Non-Repeatable Reads) :
예를 들어, 트랜잭션 T2 A 구좌의 값을 두 번 반복해서 읽는다. T2와 동시에 트랜잭션 T1이 수행되는데, T1 에서 A 구좌의 새로운 값을 쓰기 전후로 해서 T2에서
각각 A 구좌의 서로 다른 값을 읽어들이게 된다. 즉 어떤 트랜잭션에서 동일한 A 구좌의 값을 매번 읽을 때마다 달라지는 경우이다(<그림 1-.> 참조).

◆ PR(Phantom Reads) :
트랜잭션 T1내에서 전체 고객의 잔액 합을 구하 는 질의를 두 번 수행한다고 가정하자. 이와 동시에 트랜잭션 T2 D 구 좌를 account 테이블에 새로 삽입한다고
가정하자. T2에서 D 구좌의 삽입을 전후로, T1에서 각각 질의를 수행하면 전체 sum() 값이 달라진다. Non-Repeatable은 동일한 구좌 A의 값이 읽을 때마다
달라지는 경우이 고, Phantom Read는 기존 구좌 A, B의 값은 동일한데, 새로 추가된 D 구좌 때문에 결과가 달라진 경우이다(<그림 1-.> 참조).

이와 같은 데이터에 대한 동시 접근으로 인한 이상 현상은 피해야 한다. 즉 트랜잭션 데이터의 일관성을 보장해야 한다. 이상적으로는 모든 이상 현상을 피하는
것이 가장 좋다. 하지 만 이들 이상 현상이 발생하지 않도록 트랜잭션을 처리하면 (예를 들어, 모든 트랜잭션이 같은 데이터를 접근한다고 가정 하자) DBMS에서
트랜잭션 처리 속도는 트랜잭션을 차례로 하나씩 수행하는 정도로 느려진다. 그러나 다행히도(현실적 으로) 모든 트랜잭션이 모든 이상 현상을 배제해야 하는 것은
아니다. 예를 들어, 어떤 트랜잭션의 경우에는 N_R, P_R 현 상은 허용할 수도 있다. 즉 데이터베이스의 동시성을 높이기 위해 어느 정도 일관성을 타협할 수도 있는
것이다. 이를 위해 각 트랜잭션 단위로 보장받기를 원하는 일관성을 지정할 수 있어야 한다.

 

오라클과 ANSI SQL 독립성 레벨의 관계

SQL표준에서 독립성 레벨 ANSI SQL 표준에서는 트랜잭션에서 보장하는 일관성 레벨 (독립성 레벨(isolation level)이라 한다)을 정의하고 있다. < 2> ANSI SQL
표준에서 정의한 트랜잭션이 지정할 수 있는 네 가지의 독립성 레벨과 각 레벨에서 허용되는 이상 현 상을 보여주고 있다(참고자료 .). 예를 들어, Read Committed
레벨로 지정된 트랜잭션은 DW, DR 현상은 허용되지 않 는 반면 NRR, PR 현상을 나타날 수 있다. 네 개의 서로 다른 독립성 레벨을 도입한 목적은 특정 트랜잭션
별로 자신에 필 요한 만큼의 독립성 레벨을 사용함으로써 동시성을 높이고, 궁극적으로 데이터베이스의 트랜잭션 처리 성능 향상을 꾀하 기 위함이다. 표준에서
이와 같은 독립성 레벨을 지정하면, DBMS 벤 더들은 각 독립성 레벨에 정의된 대로 해당 이상 현상이 발생 하지 않게 하는 기술을 구현해야 한다. 구체적인
다양한 기술 (타임 스탬프(time stamp), 검증(validation) 방식 등)에 대 해서는 참고문헌 ., ., .을 보기 바란다. 동시성에 따른 이 상 현상을 방지하기 위해 대부분의
상용 DBMS가 보편적으 로 채택한 방법이 록킹(locking) 방법이다. 쉽게 생각하면, T1에서 A 구좌의 값을 사용하고 있으면 데이터에 록을 걸어 둬 다른 트랜잭션이
A
구좌 데이터를 요청할 때, 이미 록이 걸 려있기 때문에 T1이 끝날 때까지 다른 트랜잭션의 접근을 금 지시키는 방법이라 할 수 있다. 이와 같이 대부분의 DBMS
록 방법에 의한 동시성 제어 방법을 채택하고 있지만, 실제로 독립성 레벨을 보장하는 세부적인 구현 방법은 다르다. 중요 한 것은 이들 세부적인 구현 방법에 따라
공유 데이터에 대한 동시 접근(읽기와 쓰기)이 빈번한 OLTP 환경에서 트랜잭션 처리 속도가 차이가 많이 난다는 것이다.

 

오라클에서 지원하는 독립성 레벨

이제부터는 오라클 DBMS를 기준으로 어떤 독립성 레벨을 지원하고, 구체적으로 어떤 구현 방법을 통해 데이터의 일관 성을 보장하는지에 대해 살펴보겠다. 오라클은
두 개의 독립 성 레벨, Read Committed Serializable을 지원한다. <그림 2>는 오라클의 두 독립성 레벨과 SQL 표준에서 정의한 독립 성 레벨의 관계를 보여주고
있다. 우선 오라클에서 지원하는 Serializable SQL 표준의 Serializable과 똑같이 네 가지 이상 현상을 모두 방지해준다. 다음으로 오라클의 Read Committed
SQL
표준의 Read Committed와 이름은 같지만 의미가 다소 다르다. 즉 오라클 의 Read Committed가 좀더 엄격한 데이터 일관성을 보장해



<그림 3> 록의 개념


준다. SQL 표준에서와 마찬가지로 LU, DR 현상도 배제할 뿐더러, 제한적이기는 하지만 커서 안정성(cursor stability) 이라는 성질까지 제공한다. 자세한 사항은
참고자료 .을 참 조하기 바란다. 오라클에서 SQL 표준과 다른 독립성 레벨을 지원하는 이 유는 . SQL 표준의 Read Uncommitted처럼 DW 현상만 방지하는 레벨은
비즈니스 적으로 거의 쓸모 없기 때문에 명 시적으로 포함시키지 않고, . SQL 표준의 Repeatable Read의 경우, 뒤에서 설명할 오라클의 다중 버전 기반의 읽 기
일관성(multi-versioning based read consistency)이라는 메커니즘에 의해 Serializable 레벨을 효과적으로 지원하기 때문에 명시적으로 포함시키지 않았다.
즉 오라클 입장에서는 SQL 표준의 두 가지 레벨의 독립성, Repeatable Read Serializable의 지원에 필요한 오버헤드가 거의 동일하다. 반 면, 다중 버전 기반이
아닌 DBMS의 경우(IBM DB2 MS SQL 서버 등)에는 SQL 표준의 Repeatable Read Serializable 레벨을 지원하는데 드는 오버헤드가 크게 차이 가 나기 때문에
두 레벨을 구분해야 한다.

오라클 동시성 제어 기술의 핵심 오라클 동시성 제어 기술은 록 기반이라는 점과 다중 버전 기 반의 읽기 일관성 제공이라는 두 가지 특징을 갖는다. 여기서 는 오라클
동시성 제어 개념을 논리적으로 쉽게 이해할 수 있 게 설명한다. 실제 세부적이고 구체적인 내용은 설명과 다를 수 있음을 밝혀둔다.

 

록킹

우선 록은 두 개 이상의 트랜잭션이 공통으로 접근하는 데이 터에 대해 어떤 하나의 트랜잭션이 사용중이면 다른 트랜잭션 이 해당 데이터를 접근하지 못하게 막는다
(blocking). 그렇게 함으로써 데이터 값이 이상하게 바뀌는 것을 막는데 사용되는 것이 록킹 방법이다. <그림 3>은 오라클 록의 개념을 보여주고 있다. 트랜잭션 T1
T2가 거의 동시에 A 구좌의 튜플을 접근해서 잔액을 바 꾸려고 한다. 그런데 T1이 먼저 A 구좌 튜플을 접근했을 경 우, A=150에 의해 최초로 A 구좌 잔액을
바꾸었다고 하자. 그러면 A 구좌의 튜플(레코드) 앞 부분에 이 튜플이 이미 T1 에 의해 쓰기가 발생되었으므로 록 되었음을 표시한다(그림 에서는 개념적으로‘Yes"라고
표시했다). T1의 쓰기 바로 다 음에 T2 A 구좌의 잔액을 200으로 바꾸기 위해 해당 튜플 을 접근하면, 이미 그 튜플이 록 되었으므로 T2 T1이 종료 할 때까지
기다려야 한다. T2 T1에 의해 막힌(blocked) 상태가 된다. 트랜잭션 T1이 종료하면 A 구좌 튜플의 록 여부가‘No"로 바뀌고, 이때 T2 A 구좌의 잔액을 200으로
바꾸는 연산을 시작할 수 있다. 한 가지 주목할 점은 록 기능은 기본적으로 < 그림 1> DR 현상을 방지하는 것이다. <그림 3>의 경우 T1 은 종료될 때까지 자신이 쓴 A
구좌의 값이 다른 트랜잭션에 의해 바뀌는 일은 일어나지 않도록 보장한다. 다른 DBMS와 비교해 오라클 록 기능은 두 가지 특징이 있다. 첫째 특징은 우선 록 정보가
튜플에 직접 기록된다는 점이다. 다른 DBMS의 경우 대부분 따로 록 테이블이라는 정보를 이용하기 때문에 록이 많이 발생하는 경우 성능 저하의 한 요 인(
에스컬레이션(lock escalation)에 의한 동시성의 저하) 이 되기도 한다. 둘째 특징은 기본적으로 읽기 관련한 록은 발 생하지 않고, 항상 쓰기에 의한 록만 설정된다는
것이다. 즉 오 라클에서는 <그림 3>처럼 같은 튜플에 대해 두 개의 트랜잭션 에 쓰기(쓰기를 할 때만) 충돌이 발생해 한 트랜잭션이 기다려 야 한다는 점이다. 다른
DBMS
와 달리, 동일한 데이터에 대해 . 어떤 트랜잭션이 수행한 쓰기가 다른 트랜잭션의 읽기를 막지 않고, . 어떤 트랜잭션의 읽기가 다른 트랜잭션의 쓰기 를
방해하지 않는다. 이 이유는 뒤에서 설명할 다중 버전 기반 읽기 일관성과 관련해서 설명하겠다. 결국 이러한 성질 때문 에, 동일한 데이터에 대해 여러 트랜잭션이
동시에 접근할 가 능성이 많을수록 다른 DBMS에 비해 동시성이 높아지고, 결 국은 트랜잭션의 처리량(through-put)이 많아질 수 있다. 록 관련해서 반드시 설명해야
할 기능이 데드 록(dead lock) 개념이다. <그림 4>는 데드 록의 한 예를 보여주고 있는 데, T1 A, B 순서대로 잔액을 모두 200으로 바꾸고, T2는 이와 반대로
잔액을 300으로 바꾸는 트랜잭션이다. 그런데 우연찮게 두 트랜잭션이 거의 동시에 수행되어 T1 A 구좌 잔액을 200으로 바꾸고, T2 B 구좌 잔액을 300으로
바꾸 었다고 하자. 이후 T1 B 구좌 튜플을, T2 A 구좌 튜플을 바꾸기 위해 접근할 때, 이미 이 튜플들은 T2, T1에 의해 록 되어 있다. 따라서 서로 끝나기를
기다리는 상태-무한정 서로 끝나기를 기다리는 상태-, 데드 록 상태를 유발하게 된다. 이 경우 오라클은 일정 시간이 지난 후에, 두 트랜잭션이 데드 록 상태를
유발한 것을 발견하고, T1 T2 중에 하나를 선택 해 데드 록이 발생한 사실을 알리고, 해당 트랜잭션을 수행 중 인 사용자는 트랜잭션을 취소(rollback)할지를
결정한다. 여 기서도 주목할 점은, 오라클의 경우 쓰기만 서로 막기 (blocking) 때문에 읽기-쓰기가 서로 막는 다른 DBMS에 비 해 데드 록 발생 가능성이 훨씬
낮다는 점이다.


 


데드 록(dead lock)의 개념

 

다중 버전 기반의 읽기 일관성

우선 <그림 1> DR 현상을 이용해 오라클의 다중 버전 기 반의 읽기 일관성을 설명하겠다. <그림 5-.> DR 현상을 다시 그렸는데, 앞서의 설명을 되새기기 바란다.
<
그림 5- .>는 다중 버전의 개념과 이를 이용한 오라클의 읽기 일관 성 기본 개념을 잘 보여준다. 설명하기에 앞서, 트랜잭션 T1, T2의 문장 옆에 있는 ( )로 표시한 것은
각 문장이 수 행되는 논리적인 시점을 보여준다. 예를 들어 T1 Read A, B는 시점 1에 수행되었고, T2 Select 문은 시점 2에 시작해서 시점 4에 끝남을 의미한다.
우선 시점 3에서 T1 A 구좌에 새로운 값을 쓰면 오라클은 이전의 A 구조 값 을 기록해둔다. 따라서 논리적으로는 A 구좌의 튜플이 시점 3을 전후로 두 개의 버전이
유지된다. 그리고 시점 2에서 시작한 T2 SELECT문이 A 튜플을 접근할 때, 오라클은 SELECT문의 시작 시점 2 이후에 다른 트랜잭션에 의해 변경되었음을 확인하고,
이 튜플의 시점 2에서의 버전 값을 읽는다. 결국 T2 SELECT문은 T1에 의해 변경된 50을 읽는 게 아니라, SELECT문이 시작할 그 시점의 스냅샷 상 태의 일관성
있는 계산을 하게 된다. 따라서 DR 현상을 피 하게 된다.


오라클의 다중 버전 기반 읽기 일관성


주목할 점은 A 구좌가 T1에 의해 새로 쓰기가 일어났음에 도, T2 A를 읽을 때는 해당 레코드에서 록이 풀리기를 기다 리는 것이 아니라 이전의 버전 정보를
읽는다는 것이다. 결국 T1의 쓰기가 T2의 읽기를 막지 않는다는 점이다. 즉 앞서 기 술한 대로, 다중 버전 기반의 읽기 일관성 메커니즘은 트랜잭 션들이 서로
막지 않고 최대한 동시에 진행할 수 있도록 해줌 을 알 수 있다. 그러나 다중 버전에 기반하지 않는 DBMS의 경우(IBM, MS SQL 서버), DR 현상을 피하기 위해서는
 <그림 5-.> 상 태에서 T1의 쓰기 록이 T2의 읽기를 막는다. 또한 <그림 1-. >처럼 NRR 현상을 막기 위해서는 읽기 록이 다른 트랜잭션 의 쓰기를 막을 수도 있다


롤백 세그먼트의 역활

오라클에서는 실제로 다중 버전 정보를 어떻게 유지할까? 특 정 튜플의 값이 바뀌게 되면, 해당 튜플의 변경 내용을 롤백 세그먼트(Rollback Segment)라는
 디스크 공간에 기록해둔 다. 그리고 나중에 해당 튜플을 읽기 위해 접근할 때, 다른 트 랜잭션에 의해 변경된 상태라면 현재 튜플의 값과 롤백 세그 먼트에
기록된 변경 내용을 조합해 이전 튜플의 버전을 생성 해낸다. 예를 들어, <그림 5-.>처럼 트랜잭션 T1 A 구좌 값을 100에서 50으로 바꿀 때 롤백 세그먼트에는
A
구좌 튜 플의 잔액 애트리뷰트 값을 100에서 50으로 바꾸었다고 기록 해둔다. 이후 T2 트랜잭션에서 시점 2에서의 A 구좌 튜플의 버전을 필요로 할 때는,
현재의 A 구좌 잔액 100과 롤백 세그 먼트에 기록된 50으로 바뀐 정보를 합해 잔액 100을 갖는 A 구좌 튜플의 버전을 만들고 T2에서는 그 버전을 이용하게 된 다
(<그림 6> 참조. 롤백 세그먼트는 꽉 차게 되면 다시 앞부분 을 원형 리스트(circular list) 형태로 재사용하게 된다). 즉 롤백 세그먼트는 오라클의 다중 버전 기반
읽기 일관성 을 위해 이전의 데이터 값을 기록해두는 역할을 한다. 그렇지 만 롤백 세그먼트의 용량이 무한정 크지는 않기 때문에 아주 오래 전 시점의 특정 튜플의
값을 복원할 수는 없다. 예를 들 어, <그림 5-.>에서 T2 SELECT문의 account 테이블이 엄청나게 커서 SELECT문 수행을 시작한 지 2시간이 지나서 A 구좌에
접근하게 되었다고 하자. 그런데 T2 시작 직후에 다 른 트랜잭션에 의해 A 구좌 값이 바뀌었고 바뀐 내용을 롤백 세그먼트에 기록해 두었는데, 2시간 동안 데이터베이스
내의 변경 내용이 너무 많아서 롤백 세그먼트의 A 구좌 변경 내용 이 최근의 변경 내용을 기록하기 위해서 덮어 써버렸다고 가 정하자. 그럼 T2 2시간 뒤에
A
구좌를 접근하게 될 때, 두 시간 전 시점의 A 구좌 값을 복원할 수 없다. 이런 경우에 오 라클에서는 그 유명한‘ORA-01555: Snapshot Too Old"라 는 메시지를
받게 된다. 이와 같은 롤백 세그먼트의 크기에 따 른 문제를 줄이기 위해 오라클9i에서는 롤백 세그먼트 대신에 UNDO 테이블 스페이스를 이용해 좀더 편리하게
롤백 정보 를 관리하는 기능을 제공한다. 롤백 세그먼트는 다중 버전 기반의 읽기 일관성을 가능하 게 해주는 역할 이외에도, 실제 트랜잭션을 수행하다 사용 자가
해당 트랜잭션의 수행을 취소할 경우(Rollback 명령 어 수행), 데이터베이스의 상태를 원래대로 복구하는데 필 요하다.


롤백 세그먼트

 

트랜잭션 관련 명령어 및 주의 사항

오라클에서 사용하는 트랜잭션 관련 명령어를 SQL *Plus 환 경을 기준으로 설명하겠다.

트랜잭션 시작 : SQL*Plus에서는 트랜잭션의 시작을 알리는 명령어는 따 로 없고 DML 문을 수행하게 되면 트랜잭션의 시작으로 인식한다.

트랜잭션 종료 : 사용자가 트랜잭션을 정상적으로 종료하고자 사용하는 것이 커밋 명령이다. 이 명령어가 수행되면 트랜잭션에서 이뤄진 모든 결 과는
데이터베이스에 저장된다(지속성 보장). 다음 예는 하나의 select문 과 update문으로 구성된 트랜잭션을 수행한다.

SQL> select * from emp where ename = ‘KING";
SQL> update emp set sal = 100000 where ename = ‘KING";
SQL> commit;

트랜잭션 철회 : 트랜잭션 수행 도중에 지금까지 트랜잭션 내에서 수행한 내 용을 모두 취소.종료하고자 할 때 사용하는 것이 롤백 명령이다. 바로 앞의
예에서 커밋 대신에 롤백을 수행하면‘KING" sal가 원래대로 복구된다.

트랜잭션의 독립성 레벨 지정 : 독립성 레벨은 개별 트랜잭션 별로 지정해 사용한다. 오라클에서 새로 시작하는 트랜잭션의 독립성 레벨을 지정하는
방법은 다음과 같다. 디폴트로 오라클의 독립성 레벨은 read committed 모드이다.

SQL> set transaction isolation level serializable; /* 또는
read committed */

현재 세션의 이후 모든 트랜잭션의 독립성 레벨을 지정하는 방법은 다음과 같다.

SQL> alter session set transaction isolation_level =
serializable; /*
또는 read committed */

문장 vs. 트랜잭션 단위 읽기 일관성 : 오라클의 read committed 레벨의 경우 읽기 일관성이 문장 단위로 해당 문장의 수행 시작 시점을 기준으로 제공된다.
예를 들어, 다음과 같이 한 트랜잭션 내에서 똑같은 SELECT문 을 두 번 수행하게 되면 서로 다른 sum() 값이 나올 수가 있는데, 이는 PR 현상이 허용되기 때문이다.

SQL> set transaction isolation read committed;
SQL> select sum(sal) from emp;
SQL> ...
SQL> select sum(sal) from emp;
SQL> commit;
read commit 레벨은 트랜잭션 개별 문장의 수행 시작 시점의 스냅샷을 보여준다. 반면에 serializable 레벨의 경우 트랜잭션 내의 모든 문장을 수행할 때,
트랜잭션 시작 시점의 데이터베이스 스냅샷을 보여준다.
SQL> set transaction isolation level serializable;
SQL> select sum(sal) from emp;
SQL> ...
SQL> select sum(sal) from emp;
SQL> commit;
이 경우는 첫 번째 select 문의 수행 시작 시점의 데이터베 이스 스냅샷 값을 기준으로 두 문장 모두 같은 sum() 값을 구 하게 된다.

◆ DDL 문장 : 테이블, 인덱스 생성과 같은 DDL(Data Definition Language) 문장은 그 문장 자체로 하나의 트랜잭션을 이룬다.


DBMS에 대한 정확한 이해 필요

이번 회에서는 관계형 DBMS의 심장 역할을 하는 트랜잭션 관리에 대해 동시성 제어의 기본 원리를 중심으로 살펴봤다. 트랜잭션의 개념을 비즈니스 측면, 기술적인
측면에서 알아봤 고, 기술적인 측면에서 DBMS가 트랜잭션을 지원하기 위해 서는 동시성 제어 모듈과 회복 모듈이 필요함을 설명했다. 특 히 동시성 제어와 관련해
데이터에 대한 동시 접근으로 발생 할 수 있는 이상 현상을 알아봤고, SQL 표준에서 이상 현상 들의 허용 여부로 다양한 독립성 레벨을 지원함을 설명했다. 그리고
오라클 DBMS를 기준으로 지원하는 독립성 레벨들, 그 독립성 레벨을 지원하기 위한 핵심 기술-록과 다중 버전 기반 읽기 일관성 개념-을 알아봤다. 개별 DBMS
별로 지원하는 독립성 레벨은 조금씩 다르고, 이를 구현하는 내부 기술도 모두 다르다. 때문에 이 차이점이 트랜잭션 처리 속도에 어떤 영향을 미치는지를 정확하게
이해 하는 것은 어떤 DBMS를 선택할 것인가에 결정적인 요소가 된다. 또한 특정 DBMS의 동시성 제어와 관련한 장?단점, 한 계점 등을 제대로 이해하는 것은
데이터베이스 성능을 극대화 하는 필수 조건이다.