본문 바로가기
CS/DataBase

격리수준이란

by BK0625 2026. 3. 12.
반응형

데이터베이스 트랜잭션 격리 수준 (Transaction Isolation Levels)

데이터베이스 트랜잭션의 격리 수준은 여러 개의 트랜잭션이 동시에 실행될 때, 한 트랜잭션이 다른 트랜잭션의 변경 사항을 어느 정도까지 '볼 수 있는지'를 정의하는 기준입니다. 이는 데이터의 일관성과 무결성을 보장하면서도, 시스템의 동시성(처리량)을 최적화하기 위한 중요한 균형점입니다.

SQL 표준은 4가지 주요 격리 수준을 정의하고 있으며, 각 격리 수준은 특정 동시성 문제(Anomaly)를 방지하는 정도가 다릅니다.

트랜잭션의 4가지 속성 (ACID) 복습

격리 수준을 이해하기 전에, 트랜잭션의 ACID 속성 중 'Isolation'이 무엇인지 다시 상기하는 것이 좋습니다.

  •  A - Atomicity (원자성): 트랜잭션 내의 모든 작업은 전부 실행되거나, 아니면 전부 실행되지 않아야 합니다. (All or nothing)
  •  C - Consistency (일관성): 트랜잭션이 성공적으로 완료되면, 데이터베이스는 언제나 일관된 상태를 유지해야 합니다.
  •  I - Isolation (격리성): 여러 트랜잭션이 동시에 실행될 때, 각 트랜잭션은 마치 다른 트랜잭션이 없는 것처럼 독립적으로 실행되어야 합니다. (이것이 격리 수준의 핵심)
  •  D - Durability (영속성): 트랜잭션이 성공적으로 커밋되면, 그 변경 사항은 영구적으로 데이터베이스에 저장되어야 합니다.

동시성 문제 (Concurrency Anomalies)의 3가지 유형

격리 수준은 다음 세 가지 주요 동시성 문제를 방지하는 것을 목표로 합니다. 낮은 격리 수준에서는 이러한 문제들이 발생할 수 있습니다.

  1. Dirty Read (더티 리드 / 미확정 읽기):
    •  정의: 한 트랜잭션 A가 다른 트랜잭션 B가 아직 커밋(Commit)하지 않은 변경된 데이터를 읽는 현상입니다.
    •  문제점: 만약 트랜잭션 B가 나중에 롤백(Rollback)된다면, 트랜잭션 A는 존재하지 않는(되돌려진) 데이터를 읽게 되어 잘못된 결정을 내릴 수 있습니다. 가장 심각한 동시성 문제입니다.
    •  예시:
      1. (계좌 잔액 1000원)
      2. 트랜잭션 A 시작
      3. 트랜잭션 B 시작: 계좌 잔액을 1000원 -> 500원으로 변경 (아직 커밋 안함)
      4. 트랜잭션 A: 계좌 잔액 조회 -> 500원 (트랜잭션 B의 미확정 변경분을 읽음: Dirty Read 발생!)
      5. 트랜잭션 B: 롤백 (계좌 잔액 다시 1000원)
      6. 트랜잭션 A: 500원인 줄 알고 어떤 계산을 계속 진행 -> 잘못된 결과 도출.
  2. Non-Repeatable Read (반복 불가능 읽기):
    •  정의: 한 트랜잭션 A가 동일한 SELECT 쿼리를 두 번 실행했을 때, 그 사이에 다른 트랜잭션 B가 해당 데이터를 UPDATE하고 커밋하여 두 번의 SELECT 결과가 달라지는 현상입니다.
    •  문제점: 트랜잭션 A는 동일한 데이터를 두 번 읽었는데 결과가 달라져서 혼란을 겪거나, 비즈니스 로직에 오류를 유발할 수 있습니다. (행의 '값'이 변경됨)
    •  예시:
      1. (상품 가격 1000원)
      2. 트랜잭션 A 시작
      3. 트랜잭션 A: 상품 가격 조회 -> 1000원
      4. 트랜잭션 B 시작: 상품 가격을 1000원 -> 1200원으로 변경하고 커밋
      5. 트랜잭션 A: 상품 가격 다시 조회 -> 1200원 (Non-Repeatable Read 발생!)
      6. 트랜잭션 A: 첫 번째 1000원 기준으로 하려던 계산이 꼬임.
  3. Phantom Read (팬텀 리드 / 유령 읽기):
    •  정의: 한 트랜잭션 A가 특정 조건을 가진 행들을 SELECT 쿼리로 두 번 조회했을 때, 그 사이에 다른 트랜잭션 B가 해당 SELECT 조건에 해당하는 새로운 행을 INSERT하고 커밋하여 두 번째 SELECT 결과에 새로운(유령 같은) 행이 나타나는 현상입니다. (행의 '개수'가 변경됨)
    •  문제점: 집계 함수(COUNT, SUM)를 사용하는 쿼리에서 특히 문제가 될 수 있으며, 데이터셋의 일관성을 기대하는 로직에 혼란을 줍니다.
    •  예시:
      1. (학생 목록: 철수, 영희)
      2. 트랜잭션 A 시작
      3. 트랜잭션 A: '남학생' 목록 조회 -> '철수'
      4. 트랜잭션 B 시작: 새로운 남학생 '민수'를 INSERT하고 커밋
      5. 트랜잭션 A: '남학생' 목록 다시 조회 -> '철수', '민수' (Phantom Read 발생!)
      6. 트랜잭션 A: '남학생 수'를 세는 로직이 두 번의 조회에서 다른 결과를 얻음.

SQL 표준의 4가지 격리 수준

이제 각 격리 수준이 어떤 동시성 문제를 방지하는지 알아보겠습니다. (아래로 갈수록 격리 수준이 높아지고, 동시성 문제는 줄어들지만, 성능은 저하될 수 있습니다.)

격리 수준 Dirty Read 방지 Non-Repeatable Read 방지 Phantom Read 방지 설명

1. READ UNCOMMITTED 가장 낮은 격리 수준. 다른 트랜잭션이 아직 커밋하지 않은 데이터를 읽을 수 있습니다. 모든 동시성 문제 발생 가능. 성능은 가장 빠르지만, 데이터 일관성 최악. 거의 사용되지 않음.
2. READ COMMITTED 다른 트랜잭션이 커밋한 데이터만 읽을 수 있습니다. Dirty Read는 방지하지만, Non-Repeatable Read와 Phantom Read는 발생 가능. 대부분의 애플리케이션에서 가장 많이 사용되는 기본 격리 수준 중 하나 (Oracle, PostgreSQL 기본).
3. REPEATABLE READ ❌(PostgreSQL) / ✅(MySQL InnoDB) 한 트랜잭션 내에서 동일한 데이터를 여러 번 읽어도 항상 같은 값을 보장합니다. Dirty Read와 Non-Repeatable Read는 방지. 하지만 Phantom Read는 여전히 발생할 수 있습니다. (단, MySQL InnoDB는 Next-Key Lock으로 Phantom Read도 방지하려고 노력함)
4. SERIALIZABLE 가장 높은 격리 수준. 모든 동시성 문제를 방지하여, 마치 트랜잭션들이 순차적으로 실행된 것처럼 완벽하게 격리됩니다. 데이터 일관성은 최고지만, 동시성이 크게 저하되어 성능이 가장 느립니다. 복잡한 분석이나 금융 거래처럼 엄격한 데이터 일관성이 요구될 때 사용.

각 격리 수준의 자세한 설명

1. READ UNCOMMITTED (커밋되지 않은 읽기)

  • 설명: 가장 낮은 격리 수준입니다. 한 트랜잭션이 다른 트랜잭션이 아직 커밋하지 않은 데이터를 읽는 것을 허용합니다. (즉, Dirty Read가 발생할 수 있습니다.)
  • 장점: Lock을 거의 걸지 않으므로 동시성이 매우 높고 성능이 가장 빠릅니다.
  • 단점: 데이터의 신뢰성이 매우 낮아 실제 애플리케이션에서는 거의 사용되지 않습니다. (로그 분석 등 데이터의 일관성이 중요하지 않은 경우 가끔 사용될 수 있음)

2. READ COMMITTED (커밋된 읽기)

  • 설명: 다른 트랜잭션이 커밋한 데이터만 읽을 수 있습니다. 따라서 Dirty Read는 발생하지 않습니다. 그러나 한 트랜잭션 내에서 같은 쿼리를 두 번 실행했을 때, 그 사이에 다른 트랜잭션이 커밋되면 결과가 달라질 수 있습니다. (Non-Repeatable Read, Phantom Read 발생 가능)
  • 장점: Dirty Read를 방지하면서도 REPEATABLE READ나 SERIALIZABLE보다 높은 동시성을 제공합니다.
  • 단점: Non-Repeatable Read와 Phantom Read가 발생할 수 있어, 동일한 데이터에 대한 반복적인 읽기 일관성이 필요한 경우에는 부적합합니다.
  • 사용 예: Oracle과 PostgreSQL의 기본 격리 수준입니다. 대부분의 웹 애플리케이션처럼 빠른 응답과 높은 동시성이 요구되면서도, "최근 커밋된 데이터"를 읽는 것이 중요한 경우에 적합합니다.

3. REPEATABLE READ (반복 가능한 읽기)

  • 설명: 한 트랜잭션 내에서 동일한 쿼리를 여러 번 실행했을 때, 항상 같은 결과를 반환함을 보장합니다. 즉, Dirty Read와 Non-Repeatable Read를 방지합니다.
    • PostgreSQL: MVCC를 사용하여 트랜잭션이 시작된 시점의 스냅샷을 읽기 때문에, Non-Repeatable Read와 Phantom Read 모두 방지됩니다. (PostgreSQL의 REPEATABLE READ는 SQL 표준의 SERIALIZABLE에 가깝게 동작합니다.)
    • MySQL InnoDB: MVCC와 **Next-Key Lock (Gap Lock + Record Lock)**을 사용하여 Non-Repeatable Read와 Phantom Read를 방지합니다. (Gap Lock은 행과 행 사이의 "간격"에 Lock을 걸어 INSERT를 방지합니다.)
  • 장점: 데이터의 일관성이 매우 높으면서도, SERIALIZABLE보다는 동시성이 좋습니다.
  • 단점: 여전히 Phantom Read가 발생할 수 있습니다 (SQL 표준 기준, MySQL InnoDB는 이를 방지하려 노력함). Lock 사용이 늘어나 READ COMMITTED보다 동시성이 낮아집니다.
  • 사용 예: MySQL InnoDB의 기본 격리 수준입니다. 특정 데이터셋에 대한 반복적인 계산이나 분석이 필요한 경우에 사용됩니다.

4. SERIALIZABLE (직렬화 가능)

  •  설명: 가장 높은 격리 수준입니다. 모든 동시성 문제를 (Dirty Read, Non-Repeatable Read, Phantom Read) 완벽하게 방지합니다. 마치 모든 트랜잭션이 순차적으로(하나씩) 실행된 것처럼 동작하여, 어떤 트랜잭션도 다른 트랜잭션의 변경 사항에 영향을 받지 않습니다.
  •  장점: 데이터 일관성을 완벽하게 보장합니다.
  •  단점: Lock 경합이 매우 심해져 동시성이 가장 낮고 성능이 크게 저하됩니다. 복잡한 쿼리가 많거나 트랜잭션 시간이 길어지면 시스템의 처리량이 급격히 감소할 수 있습니다.
  •  사용 예: 엄격한 데이터 일관성이 절대적으로 요구되는 금융 거래 시스템, 재고 관리 시스템 등에서 사용될 수 있지만, 성능 때문에 매우 신중하게 적용해야 합니다.

정리하자면:

  • 격리 수준이 낮을수록: 동시성은 높아지고, 성능은 좋지만, 데이터 일관성 문제는 증가합니다.
  • 격리 수준이 높을수록: 데이터 일관성은 완벽해지지만, 동시성은 낮아지고 성능은 저하됩니다.

애플리케이션의 요구사항(데이터 일관성의 중요도, 예상되는 동시성 트래픽)에 따라 적절한 격리 수준을 선택하는 것이 중요합니다. 대부분의 웹 애플리케이션에서는 READ COMMITTED나 REPEATABLE READ (데이터베이스의 기본 설정 또는 필요에 따라 선택)가 사용됩니다.

반응형

'CS > DataBase' 카테고리의 다른 글

Postgresql  (1) 2026.03.12
redo log(mysql 8.0)  (0) 2025.09.16
[DB] Prepared Statement란?  (0) 2025.06.10
[DataBase] 인덱스란?  (1) 2025.03.26
[DB] MVCC(다중 버전 동시성 제어)  (0) 2025.03.26