다중 버전 동시성 제어(MVCC, Multi-Version Concurrency Control)는 데이터베이스 시스템에서 동시성을 관리하는 기법으로, 트랜잭션이 동시에 실행될 때 읽기 작업과 쓰기 작업이 충돌하지 않도록 여러 개의 데이터 버전을 유지하는 방식입니다.
🔹 MVCC의 주요 개념
- 다중 버전 유지
- 하나의 데이터에 대해 여러 버전의 스냅샷을 저장하여 트랜잭션이 특정 시점의 데이터를 볼 수 있도록 함
- 새로운 트랜잭션이 시작되면 최신 데이터가 아닌, 트랜잭션이 시작될 당시의 데이터 버전을 읽음 (스냅샷 읽기)
- 잠금(Locking) 없이 동시성 보장
- 일반적으로 READ 작업에서 잠금을 걸지 않음 → 다른 트랜잭션이 동시에 데이터를 수정할 수 있음
- 쓰기 작업은 기존 데이터를 삭제하지 않고 새로운 버전을 생성하여 충돌을 방지함
- 트랜잭션 격리 수준과 MVCC
- READ COMMITTED: 각 쿼리는 가장 최근에 커밋된 데이터를 읽음
- REPEATABLE READ: 트랜잭션이 시작될 당시의 데이터를 유지하며 읽음
- SERIALIZABLE: 모든 트랜잭션이 순차적으로 실행된 것처럼 보이도록 동작함
- Garbage Collection(불필요한 버전 정리)
- 오래된 데이터 버전이 계속 남아있으면 스토리지 낭비가 발생할 수 있음
- 일정 시간이 지나거나 더 이상 참조되지 않는 데이터 버전은 삭제됨
🔹 MVCC의 장점과 단점
✅ 장점
- 읽기 작업과 쓰기 작업이 충돌하지 않음 → 높은 동시성 제공
- 대부분의 읽기 작업에서 잠금을 사용하지 않아 성능이 향상됨
- 트랜잭션 격리 수준을 높여도 성능 저하가 적음
❌ 단점
- 여러 버전의 데이터를 유지해야 하므로 저장 공간이 많이 필요함
- 불필요한 데이터 버전을 정리하는 추가적인 관리 작업(Garbage Collection)이 필요함
🔹 MVCC를 사용하는 대표적인 DBMS
- PostgreSQL
- MySQL (InnoDB 엔진)
- Oracle (UNDO 기반)
- Microsoft SQL Server (SNAPSHOT ISOLATION)
MVCC는 트랜잭션이 많은 환경에서 높은 동시성과 성능을 제공하는 중요한 기법이며, 대부분의 현대적인 데이터베이스에서 사용되고 있습니다.
MVCC 사용 예제
예제 1: PostgreSQL에서 MVCC 동작 확인
PostgreSQL에서는 MVCC를 활용하여 트랜잭션이 서로 영향을 주지 않고 실행될 수 있습니다.
1️⃣ 트랜잭션 1에서 데이터 조회
BEGIN TRANSACTION;
SELECT * FROM accounts WHERE id = 1;
accounts
테이블에서 id = 1
인 계정 정보를 조회
- 현재 트랜잭션이 시작될 당시의 스냅샷을 읽음
2️⃣ 트랜잭션 2에서 데이터 수정
BEGIN TRANSACTION;
UPDATE accounts SET balance = balance + 100 WHERE id = 1;
COMMIT;
id = 1
계좌의balance
를 100 증가시킴COMMIT
하면 다른 트랜잭션에서는 변경된 데이터를 볼 수 있음
3️⃣ 트랜잭션 1에서 다시 데이터 조회
SELECT * FROM accounts WHERE id = 1;
- 여전히 처음 조회했던 값이 유지됨 (스냅샷 읽기)
- 트랜잭션 1이 종료되기 전까지는 트랜잭션 2의 변경 사항을 볼 수 없음
4️⃣ 트랜잭션 1 종료 후 다시 조회
COMMIT;
SELECT * FROM accounts WHERE id = 1;
- 이제 최신 변경 사항을 반영한 데이터를 볼 수 있음
예제 2: MySQL InnoDB에서 MVCC 적용
MySQL의 InnoDB 엔진도 MVCC를 지원하며, 트랜잭션 격리 수준에 따라 동작이 달라짐
1️⃣ 트랜잭션 A에서 데이터 조회
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
SELECT * FROM orders WHERE order_id = 10;
REPEATABLE READ
에서는 트랜잭션이 시작된 시점의 데이터를 계속 읽음
2️⃣ 트랜잭션 B에서 데이터 수정
START TRANSACTION;
UPDATE orders SET status = 'shipped' WHERE order_id = 10;
COMMIT;
orders
테이블의order_id = 10
상태를'shipped'
로 변경
3️⃣ 트랜잭션 A에서 다시 조회
SELECT * FROM orders WHERE order_id = 10;
- 변경 사항을 볼 수 없음 → 트랜잭션이 시작될 때의 스냅샷을 계속 유지
4️⃣ 트랜잭션 A가 종료된 후 다시 조회
COMMIT;
SELECT * FROM orders WHERE order_id = 10;
- 이제 변경된
status = 'shipped'
데이터를 확인할 수 있음
MVCC의 활용 사례
✅ 온라인 뱅킹 시스템
- 계좌 잔액을 조회할 때, 다른 사용자가 이체하는 동안에도 이전 상태를 유지하여 읽을 수 있음
- 동시 출금 요청이 들어와도 충돌을 최소화함
✅ 전자상거래 시스템
- 사용자가 상품 목록을 조회할 때, 다른 사용자가 가격을 변경해도 기존 가격을 유지할 수 있음
- 트랜잭션을 롤백하더라도 기존 데이터를 안전하게 보호할 수 있음
✅ 분산 데이터베이스 및 클라우드 시스템
- Amazon Aurora, Google Spanner 등에서 MVCC를 활용하여 읽기 성능을 높이고 동시성을 보장함
- 데이터 일관성을 유지하면서도 높은 처리량을 제공
MVCC는 데이터베이스 성능을 향상시키면서도 데이터 정합성을 보장하는 중요한 기법이며, 트랜잭션이 많은 환경에서 매우 유용하게 활용됩니다.