결정: 어떤 격리 수준인가?
트랜잭션 격리 수준은 동시성과 일관성 간의 균형을 결정한다. 격리 수준이 높을수록 이상 현상은 줄지만 락/충돌과 재시도가 늘어난다. 이 트리는 허용할 수 있는 읽기 이상 현상(dirty, non-repeatable, phantom)을 기준으로 Read Committed, Repeatable Read/Snapshot, Serializable 중 선택을 돕는다.
dirty read를 허용할 수 있는가?
가장 기본적인 이상 현상부터 시작한다: 트랜잭션이 아직 커밋되지 않은(롤백될 수 있는) 데이터를 읽을 수 있어야 하는가? 이를 원하는 실제 애플리케이션은 거의 없으며, 대부분의 최신 엔진은 기본값으로 이미 dirty read를 방지한다. 대략적인 분석용 집계와 최대 속도가 필요한 경우에만 완화한다.
- 아니요, 커밋된 데이터만 읽어야 함
- 예, 대략적인 읽기로 충분함(드묾)
같은 트랜잭션 내에서 다시 읽을 때 같은 결과가 보여야 하는가?
dirty read를 배제했다면 다음 질문: 트랜잭션 내에서 같은 행을 두 번 읽을 때, 그 사이 다른 세션의 커밋으로 다른 값이 보이거나(non-repeatable read) 새 행이 나타나는 것(phantom)이 문제가 되는가? 보고서/계산 일관성이 필요한 로직은 대개 일관된 스냅샷이 필요하다.
- 아니요, 각 문장이 최신 커밋 데이터를 보는 것으로 충분함
- 예, 트랜잭션 전체에 일관된 스냅샷이 필요함
동시 트랜잭션이 논리적으로 완전히 순서화되어야 하는가?
일관된 읽기를 원한다. 그것으로 충분한가, 아니면 동시 트랜잭션이 하나씩 순차 실행된 것과 같은 결과를 내야 하는가(serializable)? write skew 같은 미묘한 이상 현상(예: 두 트랜잭션이 서로 다른 행을 읽고 서로를 무효화하는 방식으로 쓰는 경우)을 허용할 수 있다면 Snapshot으로 충분하고, 그렇지 않으면 완전한 직렬화가 필요하다.
- 아니요, 일관된 스냅샷으로 충분함
- 예, 어떤 동시성 이상 현상도 허용 불가
권장: Read Uncommitted(특수한 경우만)
가장 낮은 격리 수준으로 dirty read를 허용한다. 락 대기가 거의 없이 읽지만 롤백될 수 있는 데이터를 볼 수 있다. 범용 애플리케이션에는 권장하지 않는다.
권장: Read Committed(기본 OLTP)
각 문장은 해당 시점에 커밋된 최신 데이터를 보며 dirty read가 방지된다. 대부분의 엔진에서 기본값이며 일반적인 OLTP 워크로드에 최적의 동시성/일관성 균형을 제공한다.
권장: Repeatable Read / Snapshot(일관된 읽기)
트랜잭션은 시작 시점(또는 첫 읽기 시점)에 고정된 일관된 스냅샷에서 동작하며, 트랜잭션 동안 읽기 결과가 바뀌지 않는다. MVCC에서는 읽기가 쓰기를, 쓰기가 읽기를 블록하지 않는다.
권장: Serializable(완전한 격리)
가장 높은 격리 수준: 동시 트랜잭션이 직렬로(하나씩 순차적으로) 실행된 것과 같은 결과를 낸다. 모든 읽기 이상 현상과 write skew를 방지하며, 대가로 충돌이 늘고 재시도가 필요하다.