데이터베이스에서는 여러 사용자가 동시에 접근하여 데이터를 읽고, 변경할 수 있는 동시성이 중요하다.
또한, 동시성과 함께 데이터의 일관성이 보장되어야한다.
이 동시성을 제어하고 일관성을 보장해주는 방법 중 하나가 MVCC (Multi Version Concurrency Control) 다중 버전 동시성 제어이다.
■ 기존 Locking 방식의 문제점
Locking 방식의 경우, 쓰기 작업이 수행되는동안 해당 데이터를 읽거나 쓸 수 없어 동시성의 문제가 발생한다.
MVCC 를 통해 Locking 의 문제점을 해결할 수 있다.
■ MVCC 의 특징
ㆍ MVCC 는 데이터베이스의 snapshot 을 이용하여 구현된다.
ㆍ 사용자가 데이터를 변경하면 데이터를 바로 변경하는 것이 아니라 변경 전의 데이터(snapshot) 를 Undo 라는 영역에 생성한다.
ㆍ 쿼리를 수행한 시점 이후에 변경된 값을 발견하면, Undo 영역에 저장된 데이터를 복사 (CR Copy) 하고 그것을 읽는다.
ㆍ 이 snapshot 을 통해 하나의 데이터에 대해 여러 버전의 데이터를 관리할 수 있으며, 이를 통해 데이터에 대한 변경이 commit 되기 전까지의 변경 사항을 다른 사용자가 볼 수 없도록 하는 등의 제어가 가능하다.
ㆍ 또, 다른 트랜잭션에 영향을 주지 않고 해당 데이터를 접근할 수 있도록 하여 데이터베이스의 일관성을 보장한다.
■ MVCC 장점
ㆍ Lock 을 사용하지 않아 더 빠른 읽기/쓰기 작업을 할 수 있어 처리 속도가 향상된다.
ㆍ snapshot 을 이용하여 여러 트랜잭션을 동시에 실행할 수 있어 Lock 을 줄이고, 동시성이 향상된다.
ㆍ 각 트랜잭션마다의 snapshot 을 기록하기 때문에 동시 트랜잭션간 격리를 제공하여 일관성을 보장한다.
■ MVCC 단점
ㆍ 하나의 데이터에 대해 여러 버전의 데이터가 존재하기 때문에 스토리지 오버헤드가 증가할 수 있다.
ㆍ undo 블록 I/O, CR Copy 생성, CR 블록 캐싱 등과 같은 부가적인 작업의 오버헤드가 발생한다.
■ MySQL 의 MVCC
MySQL 의 InnoDB 에서는 Undo Log 를 사용하여 MVCC 기능을 구현한다.
(MyISAM 에서는 지원하지 않는다.)
아래와 같은 player 라는 테이블이 존재한다고 하자.
id | charname | level | job |
1 | 나는야전사 | 100 | 전사 |
2 | 나는야궁수 | 104 | 궁수 |
player 테이블에서 아래와 같은 UPDATE 쿼리를 실행해보자.
UPDATE player
SET level = 110
WHERE id = 1;
UPDATE 문이 실행된 순간,
MySQL 의 InnoDB 버퍼풀에 새로운 값으로 데이터가 변경이 된다.
id | level |
1 | 110 |
그리고 Undo 로그에는 변경 전의 데이터들이 복사(snapshot) 가 된다.
id | level |
1 | 100 |
위 상태에서 commit 을 하지 않은 상태라고 치자. 이때 다른 사용자가 해당 데이터를 조회하면 어떻게 될까?
이 결과는 트랜잭션 격리 수준(transaction isolation level) 에 따라 조금 달라질 수 있다.
READ UNCOMMITTED 라면 commit 되지 않은 InnoDB 버퍼풀의 변경된 데이터를 보여줄 것이고,
READ COMMITTED, REAPEATABLE READ, SERIALIZABLE 이라면 Undo 로그의 변경되기 전의 데이터를 보여줄 것이다.
Lock 을 사용했다면, 데이터를 볼 수 없었겠지만 MVCC 덕분에 commit 하지 않은 상태의 데이터를 볼 수 있는 것이다.
이 후 commit 을 하면 디스크에 변경 후 데이터로 덮어씌어진다.
만약, rollback 을 하면 Undo Log 에서 변경 이전의 데이터를 InnoDB 버퍼풀에 다시 이전 데이터로 덮어씌어질 것 이다.
■ SQL Server 의 MVCC
ㆍ SQL Server 는 기본적으로 Lock 기반의 동시성 제어 방식을 사용한다.
트랜잭션이 데이터를 읽거나 쓸 때, 다른 트랜잭션이 동시에 해당 데이터에 접근하여 충돌이 발생하는 것을 방지하기 위해 Lock 을 사용한다.
이 때 SQL Server 의 트랜잭션 격리 수준에 따라 달라질 수 있다.
ㆍ 그러나, SQL Server 의 격리 수준 중 Snapshot 격리 수준의 경우 MVCC 를 사용한다.
트랜잭션이 시작될 때 snapshot 을 생성하는데, 이는 트랜잭션이 진행되는 동안 다른 트랜잭션에 의해 변경된 데이터를 보지 않도록 한다.
ㆍ 이 때, 변경된 행의 이전 데이터는 tempdb 에 저장되며, 각 트랜잭션은 tempdb 에 저장된 snapshot 데이터를 보게 된다.
'Database' 카테고리의 다른 글
[Database] 인덱스 스플릿 (Index Split) (0) | 2024.06.22 |
---|---|
[Database] 정규화(Normalization) (0) | 2024.06.21 |
[Database] 인덱스 (클러스터드,넌클러스터드,구조,종류,생성) (1) | 2024.03.05 |
[Database] JOIN 기법의 종류 (Nested Loops Join, Merge Join, Hash Join) (0) | 2024.02.22 |
[Database] 트랜잭션 격리 수준 (Transaction Isolation Level) (0) | 2023.10.23 |