[DB] 트랜잭션 격리 수준(Transaction Isolation Level)

joyful·2021년 7월 12일
2

CS

목록 보기
4/14
post-custom-banner

1. 개요

  • 동시에 여러 트랜잭션이 처리될 때, 트랜잭션끼리 얼마나 서로 고립되어 있는지 나타내는 것
  • 특정 트랜잭션이 다른 트랜잭션에 변경한 데이터를 볼 수 있도록 허용할지 말지를 결정하는 것



2. 격리성 관련 동시성 이슈

가정) 한 트랜잭션 = t1, 다른 트랜잭션 = t2

1. Dirty Read

  • t1이 데이터에 접근하여 값을 'A'에서 'B'로 변경 후 아직 커밋하지 않은 상태에서, t2가 해당 데이터를 read하면 'B'를 읽게 됨.
  • 이 때 t1이 최종 커밋을 하지 않고 종료되면, t2가 가진 데이터가 꼬이게 됨.

2. Non-Repeatable Read

  • t1이 데이터를 Read할 때, t2가 데이터에 접근하여 값을 변경하거나 데이터를 삭제 후 커밋함.
  • 이후 t1이 해당 데이터를 다시 read하려고 하면 변경 또는 삭제된 데이터를 조회하게 됨.

3. Phantom Read

  • t1 중에 특정 조건으로 데이터를 검색하여 결과를 얻음.
  • 이때 t2이 접근하여 해당 조건의 데이터 일부를 삭제/추가하면, 종료되지 않은 t1이 다시 해당 조건으로 데이터를 조회할 경우 t2에서 추가/삭제된 데이터가 함께 조회/누락 됨.
  • 이후 t2가 롤백을 하면 데이터가 꼬이게 됨.


3. 격리수준

격리성 관련 문제점들을 해결하기 위해 ANSI 표준에서 트랜잭션의 격리성과 동시 처리 성능 사이의 Trade-off를 두고 4단계 격리수준을 나눔.

✅ LV.0 : READ UNCOMMITTED

한 트랜잭션의 변경된 내용을 COMMIT이나 ROLLBACK과 상관 없이 다른 트랜잭션에서 읽을 수 있는 격리수준

  • 장점
    • 데이터베이스나 페이지, 열 등에 잠금을 유지하는 데 드는 간접 비용이 제일 적음
    • 교착 상태에 빠질 위험이 적어 성능이 빠르고 우수함
  • 주의
    • 더티 리드(Dirty Read) 발생 가능성 존재
    • 데이터 정합성에 문제가 많으므로, 되도록이면 사용하지 않는 것이 이상적
    • 다음과 같은 경우에만 사용하는 것을 권장
      • 갱신되지 않을 과거 자료를 열람할 때
        ex) 실험실에서 전달 된 환자의 시험 결과
      • 몇몇 행이 제대로 조회되지 않아도 무관할 만큼 거대한 양의 데이터를 어림잡아 집계할 때
    • 트랜잭션 도중에 값을 얻어낼 수 있으므로, 복잡한 stored procedure나 함수가 포함된 디버깅을 할 때 중간 과정을 확인하기 위해 사용하는 경우도 존재

✅ LV.1 : READ COMMITTED

COMMIT이 완료된 데이터만 조회 가능한 격리수준

  • 특징
    • 다른 트랜잭션에서의 변경 사항이 커밋되지 않은 경우, 실제 테이블의 값이 아닌 Undo 영역에 백업된 레코드에서 값을 가져옴
    • 커밋된 결과만 읽어오므로 Dirty Read가 발생하지 않음
    • RDB(관계형 데이터베이스)에서 대부분 기본적으로 사용되는 격리수준
  • 주의
    • Non-repeatable Read 발생 가능성 존재
    • 잠금이 발생하므로 속도나 성능에 있어서 느릴 수 있음
    • 트랜잭션 간 고립성을 완전히 보장하지 못함
      → 각 트랜잭션의 정확도를 생명으로 하는 웹 애플리케이션 구동에는 적합하지 않음
      ex) 은행 계좌 정보 조회

✅ LV.2 : REPEATABLE READ

트랜잭션이 시작되기 전에 커밋된 내용에 관해서만 조회할 수 있는 격리수준

  • 특징
    • MySQL DBMS에서 기본으로 사용
    • 자신의 트랜잭션 번호보다 낮은(먼저 일어난) 트랜잭션 번호에서 변경(커밋)된 것만 보게 됨
      • 모든 InnoDB의 트랜잭션은 순차적으로 증가하는 고유한 트랜잭션 번호를 가짐
      • Undo 영역에 백업된 모든 레코드는 변경을 발생시킨 트랜잭션의 번호를 포함함
    • Undo 공간에 백업해두고 실제 레코드 값 변경
      • 백업된 데이터는 불필요하다고 판단되는 시점에 주기적으로 삭제됨
    • 트랜잭션이 범위 내에서 조회한 데이터 내용이 항상 동일함을 보장
    • 이미 존재하는 레코드에 대해서만 보장
  • 주의
    • 다른 사용자는 트랜잭션 영역에 해당되는 데이터에 대한 수정이 불가능함
    • 잠금이 적용되는 범위가 넓어져 성능과 속도가 느려짐
    • Phantom Read 발생 가능성 존재
      → MySQL의 InnoDB는 멀티 버전 동시성 제어를 통해 어느정도 극복(next key lock 이용)

✅ LV.3 : SERIALIZABLE

한 트랜잭션을 다른 트랜잭션으로부터 완전히 분리하는 격리수준

  • 가장 단순하면서도 엄격한 격리수준
  • INSERT되는 레코드도 고려하여 격리성 유지
  • 완벽한 읽기 일관성 모드 제공
  • 한 트랜잭션이 특정 테이블을 조회할 경우, 다른 트랜잭션은 해당 테이블의 데이터를 추가/변경/삭제할 수 없음
    → 동시처리 능력이 다른 격리수준보다 떨어지며, 성능저하 발생
  • 모든 것이 순차적으로 진행되므로 Phantom Read가 발생하지 않음
  • 데이터베이스에서 거의 사용되지 않음

📊 격리수준 별 동시성 문제 비교

Isolation LevelDirty ReadNon-repeatable ReadPhantom Read
READ UNCOMMITTEDOOO
READ COMMITTEDXOO
REPEATABLE READXXO
SERIALIZABLEXXX



📖 참고

profile
기쁘게 코딩하고 싶은 백엔드 개발자
post-custom-banner

0개의 댓글