짧은 연차동안 현업에서 3가지 RDBMS를 다뤄본 경험을 가지게 되었다.
이를 토대로 각 데이터베이스별 격리 수준(Isolation Level)에 따른 동작 원리와
읽기/쓰기 시 락 동작 방식을 비교하여 정리해보려 한다.
여러 트랜잭션이 동시에 처리될 때,
특정 트랜잭션이 다른 트랜잭션에서 변경하거나 조회하는 데이터를 볼 수 있게 허용할지 여부를 결정하는 규칙이다.
격리 수준이 낮으면 동시성(Concurrency)은 높아지지만, 데이터 정합성 문제(Dirty Read, Non-Repeatable Read, Phantom Read 등)가 발생할 가능성이 있다.
격리 수준이 높으면 데이터 일관성은 좋아지지만, 동시성 저하와 락 경합 증가가 발생할 수 있다.
MySQL InnoDB는 MVCC(Multi-Version Concurrency Control) 기반으로 동작하여 읽기 작업에서 락을 최소화하면서도, 쓰기 작업 시에는 적절한 락을 걸어 데이터 무결성을 보장한다.
| 격리 수준 | 읽기 시 락 | 쓰기 시 락 |
|---|---|---|
| Read Uncommitted | 없음 (사실상 Read Committed와 유사) | 없음 |
| Read Committed | 없음 (MVCC 스냅샷 버전 읽기) | 행 단위 배타락(X Lock) |
| Repeatable Read | 없음 (트랜잭션 시작 시점 MVCC 스냅샷 읽기) | 행 단위 배타락 + 갭 락(Next-Key Lock) |
| Serializable | 암묵적 공유 락(Shared Lock) 적용 | 행 단위 배타락 + 범위 락 유지 |
읽기 작업
쓰기 작업
PostgreSQL은 MVCC 기반이며, 락 정책과 충돌 감지 방식에 차이가 있다.
| 격리 수준 | 읽기 시 락 | 쓰기 시 락 |
|---|---|---|
| Read Uncommitted | 지원하지 않음 (Read Committed로 동작) | 해당 없음 |
| Read Committed | 없음 (MVCC 스냅샷 버전 읽기) | 행 단위 배타락(X Lock) |
| Repeatable Read | 없음 (트랜잭션 시작 시점 MVCC 스냅샷 읽기) | 행 단위 배타락(X Lock) |
| Serializable | 없음 (MVCC + SSI 적용) | 행 단위 배타락 + 범위 락 |
읽기 작업
쓰기 작업
MSSQL은 기본적으로 락 기반 동시성 제어를 사용하며, 옵션으로 MVCC 기반 Snapshot Isolation도 지원한다.
| 격리 수준 | 읽기 시 락 | 쓰기 시 락 |
|---|---|---|
| Read Uncommitted | 없음 | 없음 |
| Read Committed | 짧은 시간 동안 공유 락(S Lock) 유지 | 행 단위 배타락(X Lock) |
| Repeatable Read | 공유 락(S Lock)을 트랜잭션 종료까지 유지 | 행 단위 배타락(X Lock)을 트랜잭션 종료까지 유지 |
| Snapshot | 없음 (MVCC 스냅샷 읽기) | 행 단위 배타락(X Lock), 충돌 시 롤백 |
| Serializable | 범위 락(Key-Range Lock) 유지 | 행 단위 배타락 + 범위 락 유지 |
읽기 작업
쓰기 작업
Phantom Read는 트랜잭션 내에서 같은 조건으로 여러 번 조회할 때,
처음에는 없던 새로운 행이 다른 트랜잭션에 의해 삽입되어 결과가 달라지는 현상이다.
MySQL InnoDB는 Repeatable Read 격리 수준에서 Phantom Read를 방지하기 위해
쓰기 시 갭 락(Next-Key Lock)을 사용해,
기존 행뿐 아니라 그 사이의 인덱스 갭도 잠궈 다른 트랜잭션이 새로운 행을 삽입하지 못하게 한다.
PostgreSQL은 갭 락 대신 Serializable Snapshot Isolation(SSI) 기법을 이용해
Phantom Read를 감지하고 충돌 시 트랜잭션을 롤백함으로써 방지한다.
MSSQL은 Serializable 격리 수준에서 범위 락(Key-Range Lock)을 걸어 Phantom Read를 방지한다.
MVCC 기반과 락 기반의 차이점
격리 수준 선택 시 고려할 점