트랜잭션
1. 개요
- 산업 현장에서 쓰이는 대규모 DB에서는 동시에 수백, 수천 이상의 수많은 사용자가 접근해 DB의 각각 다른 부분뿐 아니라 동일한 한 부분에 동시에 데이터를 읽고 쓰는 일이 빈번하다. 이처럼 수많은 사용자가 동시에 DB의 같은 부분을 두고 읽고 쓰기를 하는 경우에도 각 사용자는 마치 각 사용자들의 DB에 대한 읽고 쓰기가 서로 시간 간격을 두고 차례대로 읽기/쓰기를 수행한 것과 같은 결과를 얻을 수 있도록(DB가 일관성을 유지하도록) 보장하는 것을 동시성 제어(concurrency control)이라 한다.
- DB를 운영하다 보면 DB가 항상 정상적으로 작동하는 것이 아니라 어느 순간에는 하드웨어 또는 소프트웨어 측면에서 에러가 발생해 전체 시스템이 중단되는 경우가 있다. 만약 DB 내 수많은 레코드를 차례대로 하나씩 수정하는 쿼리가 수행 중일 때 이러한 에러가 발생해 이 쿼리의 수행 도중 DB 시스템 전체가 중단됐다면, 이후 DB 시스템이 복구된 경우에 DBMS가 이전 수행하던 쿼리를 어떻게 완성할지가 문제가 된다. 모든 DBMS는 쿼리를 수행할 때마다 로그(log) 파일에 그 수행 내역을 기록해, 에러로 DB 시스템이 중단됐다가 복구된 경우에 이를 참조하여 중단된 쿼리 문제를 처리하는 회복(recovery) 절차를 수행한다. 이는 DB 시스템의 에러에도 불구하고 DB가 일관성을 유지하게 하는 한 방법이다.
- 트랜잭션(transaction)은 DB의 사용자가 DB 내 레코드들에 접근해 데이터를 읽고 쓰는 작업을 통칭하는 ‘상호작용’의 단위로, 상기한 바와 같이 동시성 제어나 회복 같은 기능을 구현함에 있어 DB의 일관성을 추구하기 위해 제시된 개념이다. 이러한 구현을 위해 트랜잭션 각 단위에 대해 보장돼야 할 여러 특성이 있다. 보통 하나의 쿼리를 한 트랜잭션으로 보지만, 필요에 따라 둘 이상의 쿼리가 하나의 트랜잭션으로 취급될 필요가 있으며 여러 DBMS가 이러한 기능을 지원한다.
2. 트랜잭션의 특성
1) 원자성(atomicity)
- 한 트랜잭션 내 모든 연산은 모두가 완전히 수행되거나 모두 전혀 수행되지 않아야 한다(all or nothing)는 특성을 원자성이라 한다. 예를 들어, ‘송금’이라는 트랜잭션은 한 사람의 계좌 잔고를 감소시킨 후 다른 사람의 계좌 잔고를 증가시키는 두 개의 쿼리가 하나처럼 이루어져야 하며, 어느 한 연산만 수행되어서는 안 된다.
- DB 시스템이 중단됐다 복구된 경우에 DBMS는 로그를 참조하여 수행이 도중에 중단된 트랜잭션의 경우 이미 이루어진 내용을 지워 트랜잭션 시작 전 상태로 되돌림으로써, 수행이 완료되었으나 아직 파일에 완전히 반영되지 않은 트랜잭션의 경우 해당 트랜잭션을 처음부터 다시 수행함으로써 트랜잭션의 원자성을 보장한다.
2) 일관성(consistency)
- 한 트랜잭션이 수행된 이후에도 DB는 수행 전과 같이 그 DB에 정해진 여러 규칙과 제약을 충족해야 한다는 특성을 일관성이라 한다. 예를 들어 트랜잭션의 과정 중에는 몇몇 레코드의 기본키 값이 null이 되거나 기본키값이 변경되어도 이를 참조하는 외래키의 값은 아직 변경되지 않은 것처럼 각 릴레이션에서 규정돼 있는 여러 규칙과 제약을 어긴 상태가 한동안 유지될 수 있다. 그러나 트랜잭션이 종료한 뒤에는 다시 원래 규정돼 있던 규칙, 제약을 모두 만족해야 한다는 것이다.
3) 고립성(isolation)
- 한 트랜잭션이 데이터를 사용하고 있어 아직 완료되기 전이라면 다른 트랜잭션은 그 데이터에 접근하지 못하게 해야 한다는 특성을 고립성이라 한다. 이는 수많은 사용자가 동시에 DB의 같은 부분에 대한 트랜잭션을 요청하는 경우에 마치 모든 사용자들의 트랜잭션을 서로 시간 간격을 두고 차례대로 수행한 것과 같은 결과를 얻을 수 있도록(동시성 제어) 하는 데 있어 필수적으로 보장돼야 하는 특성이다. DBMS의 동시성 제어 모듈이 주로 이 특성을 구현한다.
4) 지속성(durability)
- 한 트랜잭션이 완료됐다면 그 결과는 이후 DB 시스템이 중단됐다 복구되더라도 손실되지 않아야 한다는 특성을 지속성이라 한다. 이러한 특성은 반드시 트랜잭션이 완료된 경우에만 보장되며, 트랜잭션이 정상적으로 완료되지 않았다면 도중에 어느 정도 수행된 연산들이 있더라도 그 결과의 지속성을 보장하지 않는다. (DB 시스템이 중단됐다 복구된 경우에 DBMS의 회복 모듈이 로그를 참조하여 완료된 트랜잭션의 결과가 손실됐는지 여부를 검사해 지속성을 구현한다.)
3. 트랜잭션의 구현
1) 완료(commit)
- 커밋 명령어는 ‘이 지점에서 트랜잭션을 완료한다’라는 뜻을 알리는 명령어로, 모든 트랜잭션은 커밋 명령어로 종료된다. 한 트랜잭션에 담고자 하는 SQL 쿼리를 하나 이상 쓴 다음에 마지막에 커밋 명령어를 작성함으로써 하나의 트랜잭션이 구현된다.
- 트랜잭션 내 쿼리들이 오류 없이 정상적으로 수행됐다면 커밋 이후 DB의 상태는 트랜잭션 시작 전과 마찬가지로 일관성이 유지되는 상태를 갖는다.
- SQL 쿼리를 수행한 끝에 커밋 명령어가 실행되면 DBMS는 반드시 그 커밋 명령어가 있기 직전까지의 모든 SQL 쿼리를 DB에 반영해야 한다(지속성).
2) 철회(abort)
- 철회 명령어는 어떤 트랜잭션이 수행되던 도중에 트랜잭션 내 쿼리에 오류가 있는 등 그 트랜잭션이 끝까지 수행되지 말아야 할 상황임을 알게 됐을 때 여태까지 그 트랜잭션의 수행을 철회하도록 하는 명령어다. 철회 명령어가 실행되면 DBMS는 DB의 상태를 그 트랜잭션이 시작되기 이전 상태로 되돌린다.
-
철회 명령어가 실행된 직후는 트랜잭션이 아직 완료되지 않은 상태이기 때문에 DB의 일관성이 지켜지지 않는 상태일 수 있으며, DBMS가 트랜잭션 철회 절차를 종료하면 그때 DB는 다시 전과 같은 일관성을 회복한다.
-
SQL 명령어로
ROLLBACK이라 하기 때문에 보통 ‘롤백’이라고도 한다.
3) input, output
- 트랜잭션의 처리는 가장 처음으로 디스크 내 DB 파일에서 데이터를 읽어와 처리하고 그 결과는 최종적으로 디스크 내 DB 파일에 기록되게 되는데, 처리한 후 곧바로 디스크 내 DB 파일을 업데이트 하는 경우도 있지만 그러지 않고 메인 메모리 내 버퍼 공간에 일단 저장해 두었다가 일정 시간이 지난 이후에 비로소 디스크 내 DB 파일로 옮겨지게 된다. 여기서 트랜잭션의 처리를 위해 맨 처음으로 디스크 내 DB 파일에서 데이터를 읽어와 버퍼 공간에 저장하는 연산을 input, 버퍼 공간의 데이터를 최종적으로 디스크 내 DB 파일에 옮기는 연산을 output이라 한다.
4. 동시성 제어
1) 개요
- 산업 현장에서 쓰이는 대규모 DB에서는 동시에 수백, 수천 이상의 수많은 사용자가 DB를 사용하며, 이때 한 데이터에 관해 여러 사용자가 동시에 트랜잭션을 요청할 때 트랜잭션의 고립성을 고려하지 않으면 여러 문제가 일어날 수 있다. 물론 트랜잭션 요청이 동시에 들어왔더라도 마치 각 트랜잭션마다 일정 시간 간격을 두고 순서대로 요청이 들어온 것으로 취급하면(serial schedule) 여러 트랜잭션이 동시에 한 데이터에 접근한다 하더라도 고립성에 문제가 일어나지 않겠지만, 그렇게 하면 어떤 트랜잭션은 요청 시간과 완료 시간 사이 시간 차이가 너무 커지는 등의 문제가 발생할 수 있다.
- 이러한 문제를 해결하기 위해 트랜잭션을 비직렬 방식으로 처리(non-serial schedule)할 수 있으나, 특별한 원칙 없이 할 경우 트랜잭션의 고립성이 지켜지지 않는 등 여러 문제가 발생할 수 있다. 동시성 제어는 여기서 트랜잭션들을 병렬처리 하되 트랜잭션의 고립성이 유지되도록, 마치 여러 트랜잭션이 시간 간격을 두고 차례대로 들어온 것처럼 처리(serializable schedule)하도록 하는 것이다.
2) lock
- 한 트랜잭션이 어떤 데이터를 사용 중일 때 그 데이터에 다른 트랜잭션이 접근하지 못하도록 lock을 걸고 트랜잭션이 그 데이터 사용을 종료하면 그 데이터를 unlock하는 방식으로 동시성 제어를 할 수 있다.
- 데이터에 lock을 거는 방식은 크게 다음 두 가지가 있다.
-
X-lock(exclusive lock): 갱신을 목적으로 데이터에 접근할 때 사용하는 lock. 한 트랜잭션이 어떤 데이터에 X-lock을 건 경우 다른 트랜잭션은 그 데이터를 조회 또는 갱신하기 위해 X/S-lock 접근을 하려 할 때에는 앞의 트랜잭션이 종료될 때까지 기다려야 한다.
-
S-lock(shared lock): 데이터 조회를 목적으로 데이터에 접근할 때 사용하는 lock. 한 트랜잭션이 어떤 데이터에 S-lock을 건 경우 다른 트랜잭션은 그 데이터를 조회하기 위한 S-lock 접근은 자유롭게 할 수 있으나 갱신하기 위한 X-lock 접근은 앞의 트랜잭션이 종료될 때까지 기다려야 한다.
- 실제로 lock 기능 구현을 위해 메모리에 현재까지 lock을 건 데이터들의 주소를 기록해 둘 필요가 있으며, 이를 lock table이라 한다. DBMS는 트랜잭션 처리 과정에서 어떤 데이터에 lock이 걸려있는지 확인할 때마다 이 lock table을 참조한다.
- 트랜잭션의 고립성이 지켜지지 않아 발생하는 대표적 동시성 이상(concurrency anomaly) 문제로 lost update 문제가 있다. 이는 어느 한 트랜잭션이 어떤 데이터를 갱신했으나 아직 커밋을 하지 않았을 때, 다른 트랜잭션이 그 데이터가 갱신되기 전의 값을 기준으로 새로 연산을 한 후 그 값을 그 위치에 갱신하면 앞의 트랜잭션이 수행한 갱신 내용이 사라지는 문제를 말한다.
- 이 문제는 한 트랜잭션이 먼저 데이터를 수정했을 때 이와 함께 그 데이터에 X-lock을 걸고 이후 그 데이터에 대한 X-lock 접근을 차단함으로써 해결할 수 있다. 이 경우 그 데이터의 값을 갱신하기 위해 X-lock 접근을 하려 하는 트랜잭션은 X-lock을 건 트랜잭션이 종료될 때까지 대기해야 한다.
4) 2PL 프로토콜(2-phase locking protocol)
- 한 트랜잭션에서 동시성 제어를 위해 어떤 데이터에 대해 lock을 걸고 갱신을 한 경우에, 갱신이 종료됐다 해서 곧바로 unlock을 하면 언뜻 보기에 트랜잭션의 고립성을 잘 구현한 것 같지만, 예를 들어 그 트랜잭션이 그 이후에 철회된다면 그 갱신 결과를 다른 트랜잭션이 이용하는 걸 허용하는 것은 dirty read 문제를 발생시킨다. 이처럼 동시성 제어는 단순히 한 데이터의 갱신이 종료됐다는 사실만으로 곧바로 unlock하는 것으로는 구현되지 않는다.
- 2PL 프로토콜은 동시성 제어를 위한 lock/unlock 관련 프로토콜로서, 한 트랜잭션이 종료되기 전까지 lock이 필요한 모든 데이터들에 대해 연쇄적으로 lock을 걸기만 하는 단계(growing phase)와 unlock만 하는 단계(shrinking phase)를 구분하도록 하는 프로토콜이다. 예를 들어 어떤 트랜잭션이 A값과 B값을 각각 1씩 증가시키는 연산을 갖는다면, 2PL 프로토콜은 먼저 A값을 1 증가시켰다 해서 곧바로 unlock하지 않고 뒤이어 B값에 lock을 걸고 1 증가시킨다. 이 트랜잭션은 A값, B값 외에 더 lock을 필요로 하지 않으므로, 이 두 값에 대한 lock과 값의 갱신이 모두 종료되었다면 그때 비로소 unlock을 시작한다. (unlock 이전에 다른 트랜잭션에서 A값에 접근해올 경우 그 트랜잭션은 대기시킨다.)
-
lock point: 그 트랜잭션에서 필요로 하는 모든 데이터에 lock을 걸어놓은 시점.
-
shrinking phase에서 lock table을 참조하여 lock이 걸린 모든 데이터에 대해 동시에 unlock을 수행할 수도 있다.
5) 데드록(deadlock)
- 2PL 프로토콜에서는 lock point가 나타나기 전까지는 어떤 데이터에 대해서도 unlock을 하지 않는데, 이 경우 서로 다른 두 트랜잭션이 각자가 lock을 걸어놓은 데이터에 서로 접근하지 못하고 무한 대기하는 데드록이 발생할 수 있다.
- 데드록을 해소하는 방법으로 deadlock detection and recovery(데드록이 발생한 사실을 감지했을 때 어느 한 트랜잭션을 희생시킴으로써 데드록을 해소), deadlock prevention(데드록이 발생할 조건을 미리 고려해 데드록을 예방) 같은 방법이 있다.
6) multiple granularity
- 만약 어떤 DB 시스템에 주로 요청되는 트랜잭션들이 접근하는 레코드 수가 많지 않다면 각 레코드 단위로 lock을 해도 lock table을 다루는 시간은 그리 오래 걸리지 않을 수 있다. 그러나 DB 시스템에 주로 요청되는 트랜잭션들이 접근하는 레코드 수가 어마어마한 규모라면, 레코드 하나 단위로 lock을 할 경우 lock table에서 어떤 트랜잭션이 갱신/조회하려는 레코드에 lock이 걸려있는지 등을 확인하고 새로운 lock 기록을 추가하고 삭제하는 등 일련의 작업에 굉장한 시간(overhead)이 소요된다.
- 트랜잭션이 접근하는 레코드의 수가 크다면 각 레코드 단위가 아니라 보다 큰 단위(파일 블록, 릴레이션, DB 전체)를 한 단위로 lock/unlock 작업을 수행해 이러한 문제를 해결할 수 있다. 이처럼 트랜잭션이 접근하는 레코드 수에 따라 lock/unlock 작업을 수행하는 단위의 크기(granularity)가 달라지는 것을 multiple granularity라 한다.
-
일반적으로 DBMS는 트랜잭션이 접근하는 레코드 수에 따라 스스로 lock/unlock의 단위를 조정하는 기능을 제공한다.
-
granularity가 낮아지면 overhead가 커지지만 그만큼 동시에 처리할 수 있는 트랜잭션의 수가 늘어나며, 반대로 granularity가 높아지면 overhead는 작아지지만 그만큼 동시에 처리할 수 있는 트랜잭션의 수가 줄어든다(대기해야 하는 트랜잭션들이 늘어나기 때문).
7) phantom read 문제 및 그 해결
- 어느 한 트랜잭션에서 어떤 조건에 해당하는 데이터를 읽은 후 아직 커밋을 하지 않았을 때, 다른 트랜잭션이 그 조건을 충족하는 새 데이터를 DB에 추가를 하고, 그 다음에 앞의 트랜잭션이 그 조건에 해당하는 데이터를 다시 읽으면 앞의 트랜잭션은 같은 쿼리를 두 번 실행했는데 두 번째 쿼리에선 전에 없던 새 데이터가 나타난다(phantom read). 이를 phantom read 문제라 한다.
- phantom read 문제는 기존 이미 있는 레코드들에 lock을 거는 방식으로 절대 해결할 수 없는데, 기존 레코드에 lock이 걸려있다 해서 새 레코드 삽입이 기존 레코드에 걸린 lock과 충돌하는 게 아니기 때문이다.
- 트랜잭션에서 SELECT 쿼리를 실행할 때, 그 쿼리에서 사용한 조건식에 있는 필드가 인덱스를 갖는다면 그 인덱스에 lock을 걸어서 phantom read 문제를 해결할 수 있다. 예를 들어 SELECT * FROM table1 WHERE field1=1이라는 쿼리가 실행됐고 field1이라는 필드가 인덱스를 가진다 하자. 이때 이 필드의 1번 인덱스에 lock을 걸면, 이 다음에 다른 트랜잭션에서 INSERT INTO table1 VALUES(1)이라는 쿼리가 들어왔을 때 쿼리가 삽입하는 필드값의 인덱스에 lock이 걸려있다는 사실을 확인할 수 있어 이 트랜잭션을 대기시킬 수 있다.
5. 트랜잭션 고립 수준(transaction isolation level)
1) 개요
- 트랜잭션이 데이터를 읽는 부분에 대해 강력한 기준을 적용하면(X-lock 걸린 데이터 읽기 불허, long S-lock) 트랜잭션의 고립성 및 일관성이 강하게 유지되므로 동시성 이상 문제가 발생하지 않으나, 이 경우 동시처리 성능이 다소 저하될 수 있다. 따라서 SQL 표준은 트랜잭션이 데이터를 읽는 부분에 대해 보다 완화된 기준을 적용하는 것을 허용하여 고립성, 일관성 수준을 약화시키더라도 동시처리 성능을 높일 수 있도록 한다.
- 트랜잭션이 데이터를 읽는 부분에 대한 기준을 완화할 경우 다음과 같은 동시성 이상 문제가 발생할 수 있다.
-
dirty read: 어느 한 트랜잭션이 어떤 데이터를 갱신했으나 아직 커밋을 하지 않았을 때, 다른 트랜잭션이 그 갱신된 결과를 조회해 다른 연산을 수행을 한 경우에, 그 이후에 만약 앞의 트랜잭션이 어떤 이유가 있어 철회가 돼버리면 뒤의 트랜잭션은 더 이상 그 DB에 존재하지 않는 데이터를 가져다(dirty read) 연산을 수행한 셈이 돼버린다. 이를 dirty read 문제라 한다. X-lock 걸린 데이터 읽기를 허용했을 때 나타나는 문제다.
-
unrepeatable read: 어느 한 트랜잭션이 어떤 데이터를 읽고 아직 커밋을 하지 않았을 때, 다른 트랜잭션이 그 데이터를 읽어 다른 연산을 수행한 경우에, 그 이후에 만약 앞의 트랜잭션에서 그 데이터를 갱신을 하는 연산이 일어났다면 뒤의 트랜잭션은 그 이후에 그 데이터를 다시 읽어왔을 때 아까 읽었을 때와 같은 데이터를 읽었는데 두 데이터의 값이 서로 다른 상황(unrepeatable read)이 나타난다. 이를 unrepeatable read 문제라 한다. S-lock을 걸지 않거나 걸더라도 그 트랜잭션이 종료하기 이전에 S-lock을 일찍 해제할 때 나타나는 문제다.
2) 트랜잭션 고립 수준 명령어의 유형
(1) READ UNCOMMITTED
- S-lock을 걸지 않음
- X-lock 걸린 데이터 읽기: 허용
-
lost update 문제: 발생하지 않는다. X-lock이 걸려있을 시 다른 X-lock의 접근을 허용하지 않기 때문.
-
dirty read 문제: 발생할 수 있다.
-
unrepeatable read: 발생할 수 있다.
(2) READ COMMITTED
- SELECT 쿼리 수행 시 S-lock을 걸되 그 S-lock은 SELECT 쿼리 수행 종료 즉시 해제(short S-lock)
- X-lock 걸린 데이터 읽기: 불허
-
lost update 문제: 발생하지 않는다.
-
dirty read 문제: 발생하지 않는다. X-lock이 걸려있을 시 S-lock 접근을 허용하지 않기 때문.
-
unrepeatable read: 발생할 수 있다. 한번 read가 끝나면 S-lock을 풀기 때문.
(3) REPEATABLE READ
- 트랜잭션이 종료한 뒤에야 S-lock 해제(long S-lock)
- X-lock 걸린 데이터 읽기: 불허
-
lost update 문제: 발생하지 않는다.
-
dirty read 문제: 발생하지 않는다.
-
unrepeatable read: 발생하지 않는다.
6. 회복
1) 개요
- DB 시스템이 어느 한 트랜잭션의 수행 도중 중단되거나, 수행은 종료되었어도 디스크 내 저장된 DB의 정보를 갱신(output 연산)하기 전에 중단된 경우 어떤 방식으로 회복을 할지가 문제가 된다.
- DB 시스템이 중단됐다 복구된 경우에는 로그를 조회하여 각 경우마다 그에 맞는 대처를 한다.
-
트랜잭션 수행 도중 시스템 중단: 그 트랜잭션이 갱신한 데이터를 원상복구(undo)한다.
-
트랜잭션 수행이 종료됐지만 output 연산을 하지 않은 상태에서 시스템 중단: 그 트랜잭션이 갱신했던 기록이 있는 데이터를 다시 갱신(redo)한다.
2) 하드웨어에 문제가 발생한 경우
- 하드웨어 결함으로 DB 시스템이 중단됐더라도, 로그 내역이 디스크에 잘만 저장돼 있다면 이를 이용하여 회복을 할 수 있으므로 큰 문제가 되지 않는다. 그러나 디스크 결함으로 로그 내역마저 제대로 남아있지 않다면 수많은 트랜잭션 처리 내역이 완전히 사라지는 게 돼 대단히 심각한 문제가 된다. 따라서 이를 저장하는 디스크는 어떤 고장에도 견딜 수 있는 저장장치(stable storage)여야 하며, 하나가 아니라 둘 이상의 저장장치를 사용하는 것이 안전하다. 보통은 동시에 두 개의 저장장치가 하드웨어적으로 문제가 발생하는 확률이 극히 드물기 때문에 2개 정도면 충분하다고 본다.
3) 여러 장애를 처리하는 알고리즘들
-
지연 갱신: 한 트랜잭션 내 수행되는 모든 쿼리에 대해, 각 쿼리마다 그 결과를 (곧바로 로그에는 기록하나) 트랜잭션이 다 끝마친 후에 비로소 output 연산을 하는 방식. DB 시스템이 중단됐다 복구된 경우 redo 연산 수행이 필요하나 undo 연산을 수행할 필요는 없다.
- undo 연산을 수행할 필요가 없으므로, 로그 파일에 담기는 로그 레코드에는 쿼리 수행 후 변경된 결과값만 저장되고 변경 전 값은 저장되지 않는다.
-
즉시 갱신: 한 트랜잭션 내 수행되는 모든 쿼리에 대해, 각 쿼리마다 그 결과를 (곧바로 로그에도 기록하고) 곧바로 output 연산을 하는 방식(트랜잭션 종료 시까지 기다리지 않음). DB 시스템이 중단됐다 복구된 경우 로그 파일을 참조한 undo 연산 수행이 필요하며, 이미 처리한 쿼리라 하더라도 커밋이 되지 않은 이상 미완료 상태로 있을 수 있기 때문에 redo 연산도 수행할 필요가 있다.
- undo 연산 수행이 필요하기 때문에, 로그 파일에 담기는 로그 레코드에는 쿼리 수행 전 원본값과 수행 후 결과값이 모두 저장된다.
-
shadow paging: 버퍼가 가득 차 DB 정보를 갱신할 때 갱신 정보를 기존 디스크 내 그 정보가 있던 위치에 갱신하는 게 아니라 거기는 그대로 놔두고 디스크의 새로운 섹터(페이지)에 그 버퍼 내 정보를 담는 방식. 이 방식은 디스크 내 정보를 갱신하는 도중에 DB 시스템이 중단됐다 복구될 경우에 디스크 내 정보 갱신이 얼마나 이루어졌는지를 확인하고 그 지점부터 다시 갱신을 수행하는 데 유리하다.
4) 검사점(checkpoint)
- 실제 로그 파일의 크기는 매우 방대하므로, DB 시스템이 한번 중단됐다 복구됐다 해서 로그 파일에 기록된 모든 트랜잭션에 대해 redo 연산을 한다는 건 있을 수 없는 일이다.
- 실제 DBMS는 일정한 시간 간격으로 ‘지금 시점까지 종료된 모든 트랜잭션은 정상적으로 디스크에 잘 저장됐음’이라는 표시를 로그 파일에 기록하며(즉시 갱신 방식의 경우 단순히 기록으로 충분하겠지만 지연 갱신 방식의 경우 이를 위해 먼저 output 연산을 해야 한다), 이를 검사점이라 한다. 검사점을 이용해 이 문제를 간단히 해결할 수 있다. DB 시스템이 한번 중단됐다 복구됐을 때, 가장 최근의 검사점 이후 있은 트랜잭션에 대해서만 redo, undo 연산을 고려하고 그 검사점 이전 종료된 트랜잭션에 대해서는 전혀 고려하지 않으면 된다.