Post

데이터베이스 트랜잭션 격리 수준 이해하기

데이터베이스 트랜잭션 격리 수준 이해하기

데이터베이스에서 트랜잭션 격리 수준(Transaction Isolation Level)은 여러 트랜잭션이 동일한 데이터에 동시에 접근할 때 발생할 수 있는 문제를 방지하는 중요한 개념입니다. 이는 데이터의 정합성을 유지하면서 동시성을 제어하는 핵심적인 전략으로 사용됩니다.

격리 수준은 성능과 데이터 정합성 사이의 상충 관계(Trade-off)를 가집니다. 격리 수준을 낮추면 초당 트랜잭션 처리량(TPS)이 증가하여 성능은 향상되지만, 데이터 정합성이 깨질 위험이 커집니다. 반대로 격리 수준을 높이면 데이터의 안전성은 보장되지만, 시스템 전반의 성능이 저하되고 교착 상태(Deadlock)가 발생할 가능성이 높아집니다. 따라서, 애플리케이션의 요구사항에 맞는 적절한 격리 수준을 선택하는 것은 성능, 정합성, 확장성의 균형을 맞추는 데 필수적입니다.


1. 트랜잭션 격리 수준이 막고자 하는 이상 현상

ANSI SQL 표준에서는 트랜잭션 격리 수준을 정의하며, 격리 수준이 높아질수록 다음과 같은 세 가지 주요 이상 현상(Anomaly)의 발생을 순차적으로 방지합니다.

이상 현상설명
Dirty Read (더티 리드)하나의 트랜잭션이 아직 커밋되지 않은 데이터를 다른 트랜잭션에서 읽는 현상입니다. 만약 원본 트랜잭션이 롤백될 경우, 다른 트랜잭션은 유효하지 않은 데이터를 기반으로 로직을 처리하게 됩니다.
Non-Repeatable Read (반복 불가능한 읽기)한 트랜잭션 내에서 동일한 쿼리를 두 번 실행했을 때, 그 사이에 다른 트랜잭션이 데이터를 수정하고 커밋하여 두 쿼리의 결과가 다르게 나타나는 현상입니다.
Phantom Read (팬텀 리드)특정 범위의 데이터를 조회할 때, 첫 번째 쿼리에서는 없던 로우(row)가 두 번째 쿼리에서 나타나는 현상입니다. 이는 다른 트랜잭션이 새로운 데이터를 추가하고 커밋했기 때문입니다.

2. ANSI 4대 격리 수준별 상세 정보

트랜잭션 격리 수준은 네 단계로 나뉩니다. 단계가 낮을수록 동시성은 높아지지만 데이터 정합성이 위협받을 수 있고, 단계가 높을수록 데이터는 안전해지지만 성능이 저하될 수 있습니다.

격리 수준허용하는 이상 현상주요 특징 및 권장 사용처
1. READ UNCOMMITTED (RU)Dirty Read, Non-Repeatable Read, Phantom Read가장 빠른 속도를 가지며, 커밋되지 않은 데이터까지 읽을 수 있습니다. 정합성에 심각한 문제가 발생할 수 있어 운영 환경에서는 거의 사용되지 않으며, 대용량 데이터의 집계나 통계 작업에서 일시적으로 사용될 수 있습니다.
2. READ COMMITTED (RC)Non-Repeatable Read, Phantom ReadDirty Read를 방지하며, 커밋이 완료된 데이터만 읽습니다. Oracle, PostgreSQL, SQL Server 등 대부분의 상용 데이터베이스에서 기본값으로 채택하고 있습니다. 빠른 응답이 중요하고, 반복 조회가 많지 않은 일반적인 웹 애플리케이션에 적합합니다.
3. REPEATABLE READ (RR)Phantom Read트랜잭션이 시작된 시점의 데이터 스냅샷을 만들어, 트랜잭션이 끝날 때까지 일관된 데이터를 조회하도록 보장합니다. 이를 통해 Non-Repeatable Read를 방지합니다. 금융 정보, 재고 관리 등 데이터의 일관성이 중요한 시스템에 권장됩니다. MySQL의 InnoDB 스토리지 엔진의 기본 격리 수준입니다.
4. SERIALIZABLE (SR)모든 이상 현상 차단가장 엄격한 격리 수준으로, 트랜잭션을 순차적으로 실행하는 것과 동일한 결과를 보장합니다. SELECT 쿼리에도 공유 락(Shared Lock)을 설정하여 동시성을 크게 제한하므로, 성능 저하와 교착 상태 발생 가능성이 높습니다. 데이터 정합성이 극도로 중요한 금융 결제 시스템이나 회계 마감 작업 등에서 제한적으로 사용됩니다.

격리 수준별 실제 동작 예시

특정 데이터를 조회한 후, 다른 트랜잭션이 해당 데이터를 수정하고 커밋했을 때 각 격리 수준은 다음과 같이 동작합니다.

  • READ COMMITTED: 트랜잭션 내에서 동일한 데이터를 다시 조회하면 최신 커밋된 값이 반환됩니다.
  • REPEATABLE READ: 트랜잭션이 시작될 때 생성된 스냅샷을 기반으로 하므로, 다시 조회해도 처음 읽었던 값이 그대로 반환됩니다.
  • SERIALIZABLE: 다른 트랜잭션의 접근이 원천적으로 차단됩니다.

3. 격리 수준 선택을 위한 실무적 고려 사항

데이터베이스의 기본 격리 수준이 항상 최선은 아닙니다. 시스템의 특성과 요구사항에 따라 신중하게 선택해야 합니다.

  1. 데이터 정합성의 중요도
    • 금융, 재고, 쿠폰과 같이 데이터의 정확성이 최우선인 경우, REPEATABLE READ (RR) 이상의 격리 수준을 권장합니다.
    • 로그나 통계 데이터처럼 약간의 오차를 감수할 수 있는 데이터는 READ COMMITTED (RC) 수준으로도 충분할 수 있습니다.
  2. 동시성 이슈 최소화
    • 교착 상태의 발생 가능성은 READ COMMITTED에서 낮고, SERIALIZABLE에서 가장 높습니다.
    • Dirty Read만 방지해도 되는 대부분의 시나리오에서는 RC를 선택하는 것이 합리적입니다.
    • 한 트랜잭션 내에서 동일한 데이터를 여러 번 조회해야 한다면 RR이 필요합니다.
    • Phantom Read까지 방지해야 하는 특수한 상황에서는 SR을 고려하되, 성능 저하를 반드시 감수해야 합니다.
  3. 락(Lock) 전략과의 조합
    • 경합이 빈번한 데이터의 경우, RC 격리 수준에 비관적 락 (SELECT FOR UPDATE)을 함께 사용하여 데이터 정합성을 확보하는 전략이 실무에서 자주 사용됩니다.
    • 애플리케이션 레벨에서는 @Transactional 어노테이션 등을 통해 트랜잭션 단위로 격리 수준을 설정하고, 필요에 따라 특정 로직에 락을 명시적으로 사용하는 것이 효과적입니다.
This post is licensed under CC BY 4.0 by the author.