팬텀현상(Phantom Phenomenon)의 개요
- 데이터베이스 트랜잭션 처리에서 발생하는 동시성 문제 중 하나
- 한 트랜잭션이 조건을 만족하는 레코드 집합을 읽은 후, 다른 트랜잭션이 해당 조건을 만족하는 새로운 레코드를 삽입하거나 삭제하면서 발생
- 처음 읽은 레코드 집합과 후속 재조회 시의 레코드 집합이 일치하지 않는 문제
- 사용자 입장에서는 존재하지 않던 새로운 레코드가 갑자기 등장하는 것처럼 보이므로 '팬텀(유령)'이라는 표현 사용
발생 배경 및 사례
- 트랜잭션 T1이 "급여가 500만 원 이상인 사원" 조건으로 사원 테이블 조회
- 트랜잭션 T2가 같은 시점에 급여가 500만 원 이상인 신규 사원을 삽입
- T1이 같은 조건으로 다시 조회 시, 처음 조회에 없던 새로운 레코드 등장
- 비즈니스 로직 상 부정확한 처리 결과 초래 가능
팬텀충돌 발생 조건
- 다중 사용자 환경에서 병행 처리되는 트랜잭션 존재
- 조건 기반의 범위 검색(range query) 수행
- 삽입(Insert) 또는 삭제(Delete) 트랜잭션에 의해 조건 만족 레코드의 수가 변화
- 트랜잭션 격리 수준이 팬텀현상을 허용하는 수준일 경우 발생
팬텀충돌의 문제점
- 데이터 일관성(consistency) 위협
- 비즈니스 로직 오류 발생 가능성 증가
- 애플리케이션 로직 신뢰성 저하
- 트랜잭션 기반 처리 시스템에서 예측 불가능한 결과 도출
팬텀충돌과 관련된 트랜잭션 격리 수준
- Read Committed: 팬텀현상 발생 가능
- Repeatable Read: 같은 행에 대한 반복 읽기 일관성 보장, 그러나 팬텀현상 방지 불가능
- Serializable: 가장 높은 수준의 트랜잭션 격리, 팬텀현상 포함 모든 동시성 문제 방지
- Snapshot Isolation(MVCC 기반): 버전 기반 처리로 팬텀현상 일부 방지 가능
팬텀충돌 방지 기법
- 트랜잭션 격리 수준 상향
- Serializable 수준 설정을 통해 범위 조회에 대한 잠금 적용
- 단점: 시스템 전체 성능 저하 우려
- 범위 잠금(Range Lock, Predicate Lock)
- 검색 조건에 해당하는 키 범위 전체를 잠금
- 삽입 및 삭제에 대한 병행성 제어 가능
- MVCC(Multi-Version Concurrency Control)
- 트랜잭션 별로 서로 다른 스냅샷을 통해 작업 수행
- 팬텀현상 방지하면서 병행성 향상
- 의도적 테이블 잠금 사용
- INSERT, DELETE 작업이 빈번한 상황에서는 테이블 단위로 Lock 수행
- 병행성은 낮지만 일관성 우선 환경에서는 효과적
- 트랜잭션 격리 수준 상향
팬텀충돌 관련 주요 DBMS 사례
- Oracle: Serializable 트랜잭션 사용 시 팬텀현상 방지
- SQL Server: Serializable 격리 수준에서 키 범위 잠금 자동 수행
- PostgreSQL: MVCC 기반으로 Snapshot Isolation 적용
- MySQL(InnoDB): Repeatable Read 격리 수준에서 Next-Key Lock 사용하여 팬텀현상 방지
실무 적용 시 고려사항
- 무조건 Serializable 수준 사용은 시스템 부하 증가 가능
- 트랜잭션 특성에 따라 유연한 격리 수준 적용 필요
- 성능과 일관성 사이의 균형 고려
- 팬텀현상이 실제 업무 로직에 미치는 영향 평가 후 설계
정리 및 시사점
- 팬텀충돌은 다중 사용자 환경에서 범위 기반 데이터 접근 시 발생하는 특수한 동시성 문제
- 단순한 레코드 잠금으로는 해결되지 않으며, 구조적 잠금 또는 버전 관리 기법 필요
- 안정적이고 신뢰할 수 있는 트랜잭션 처리 시스템을 구축하기 위해서는 팬텀현상에 대한 정확한 이해와 제어 전략 수립이 필수
'IT Study > 데이터베이스 및 데이터 처리' 카테고리의 다른 글
🗂️ 데이터 레이크하우스 아키텍처 (Delta Lake, Iceberg) (0) | 2025.04.02 |
---|---|
🗂️ 데이터 옵스(DataOps) (0) | 2025.04.01 |
🗂️ 벡터 DB(Vector Database) (1) | 2025.04.01 |
🗂️ 관계형 데이터베이스(RDBMS) (0) | 2025.03.28 |
🗂️ 정적 SQL & 동적 SQL (0) | 2025.03.26 |