InnoDB가 Phantom Read를 피하는 법

2023. 10. 11. 23:56·DB/MySQL
반응형

Real MySQL 복습을 진행하면서 가볍게 읽고 넘어갔지만 원리가 궁금해진 부분이 생겼다.

 

InnoDB 스토리지 엔진에서는 갭 락과 넥스트 키 락을 어떻게 사용하길래 REPEATABLE READ 격리 수준에서도 팬텀 리드가 발생하지 않을까?

 

이 궁금증을 해소하고자 한다.

 

REPEATABLE READ, 갭락과 넥스트 키 락에 대한 내용은 아래 포스팅에서 확인할 수 있다.

 

https://devdebin.tistory.com/252

 

트랜잭션과 잠금

2023.10.9 복습 리팩토링 시작 트랜잭션 트랜잭션은 작업의 완전성을 보장해 준다. 즉, 정합성을 보장하기 위한 기능이다. 논리적인 작업 셋을 모두 완벽하게 처리하거나, 처리하지 못할 경우에는

devdebin.tistory.com

팬텀 리드

팬텀 리드란 다른 트랜잭션에서 수행한 변경 작업에 의해 레코드가 보였다가 안보였다 하는 현상을 의미한다.

팬텀 리드는 여러 상황에서 발생하지만 일반적으로 아래와 같은 패턴을 가진다.

  1. 특정 범위를 검색한다.
  2. 범위 결과에 작업(Create, Update, Delete)을 수행한다.
  3. 작업(Create, Update, Delete)은 원래 범위 결과에 직접적인 영향을 미친다.

쓰기 왜곡을 방지하는 가장 간단한 방법은 배타적 잠금(SELECT FOR UPDATE)을 사용하는 것이다.

그러나 언두 레코드에는 잠금을 걸 수 없다.

 

InnoDB 스토리지 엔진에서는 갭 랍과 넥스트 키 락 덕분에 REPEATABLE READ 격리 수준에서도 팬텀 리드가 발생하지 않는다고 한다.

이제 이 원리에 대해 알아보자.

팬텀 리드를 피하는 원리

핵심은 넥스트 키 락이다. 

넥스트 키락은 레코드 락 + 갭 락이다.

즉 레코드 자체에도 락이 걸리고 레코드와 바로 인접한 레코드 사이의 간격도 잠군다.

첫 번째 예시

팬텀 리드 발생 예시

  1. employee 테이블의 초기 두 레코드는 번호가 6인 트랜잭션에 의해 INSERT 됐다.
  2. 사용자 B가 번호가 10인 트랜잭션을 사용해 emp_no가  50 이상인 데이터 레코드를 SELECT FOR UPDATE 쿼리를 진행했다.
    조회한 데이터 레코드의 이름 컬럼 값은 Lara.
  3. 사용자 A가 번호가 12인 트랜잭션을 사용해 emp_no가 51인 데이터를 INSERT 했다. 이름 컬럼 값은 Georgi
  4. 번호가 10인 트랜잭션을 사용해 emp_no가 50 이상인 데이터 레코드를 SELECT FOR UPDATE하면 결과는 Lara, Georgi 결과 2건이 나오게 된다.

팬텀 리드 발생하지 않는 예시 (넥스트 키 락 사용)

  1. employee 테이블의 초기 두 레코드는 번호가 6인 트랜잭션에 의해 INSERT 됐다.
  2. 사용자 B가 번호가 10인 트랜잭션을 사용해 emp_no가  50 이상인 데이터 레코드를 SELECT FOR UPDATE 쿼리를 진행했다.
    조회한 데이터 레코드의 이름 컬럼 값은 Lara.
  3. 사용자 A가 번호가 12인 트랜잭션을 사용해 emp_no가 51인 데이터를 INSERT 했다. 이름 컬럼 값은 Georgi.
  4. 그러나 넥스트 키 락으로 인해 대기 상태가 된다. 50 이상의 영역은 갭락으로 인해 락이 걸려서 해당 영역에 레코드 삽입이 불가능하다.
  5. 추후에는 wait time out 설정에 의해 롤백된다.

두 번째 예시 (Update)

팬텀 리드 발생 예시

  1. t 테이블에 i가 21, 25,30인 레코드가 있다.
  2. 사용자 A의 트랜잭션 A가 SELECT * FROM t WHERE i > 20 FOR UPDATE;를 실행한다.
  3. 사용자 B는 INSERT INTO t VALUES(26);를 실행하고 커밋된다.
  4. 이후 트랜잭션 A에서 select * from t where i > 20 FOR UPDATE;를 수행하면 21, 25, 26, 30이 나온다.

팬텀 리드 발생하지 않는 예시 (넥스트 키 락 사용)

  1. t 테이블에 i가 21, 25,30인 레코드가 있다.
  2. 사용자 A의 트랜잭션이 SELECT문을 사용해 21, 25, 30을 조회함.
  3. 사용자 A의 트랜잭션 A가 DELETE FROM t WHERE i=25;를 실행한다. 이 시점에서는 레코드 25만 잠겨있다고 가정하자.
    또한 사용자 A의 트랜잭션은 아직 끝나지 않음
  4. 이후 사용자 B는 INSERT INTO t VALUES(26);를 실행한다. 그러나 이는 넥스트 키 락, 즉 갭 잠금으로 인해 실패한다. 
  5. 26 대신에 29, 23을 넣어도 실패한다. 21부터 30까지 모두 갭 잠금이 걸린 것 이다.
  6. 31을 넣으면 insert가 성공한다.

이렇게 넥스트 키 락을 사용해 어떻게 팬텀 리드를 막는지 원리를 알아보았습니다. 감사합니다.

참고 자료

REAL MySQL 8.0 1권

https://dev.to/lazypro/solve-phantom-read-in-mysql-e7g

 

Solve Phantom Read in MySQL

The combination of MySQL and its storage engine InnoDB is almost the most widely used relational...

dev.to

https://www.percona.com/blog/innodbs-gap-locks/

 

InnoDB Gap Locks

One of the most important features of InnoDB is the row level locking, and to accomplish this these databases require InnoDB gap locks.

www.percona.com

 

반응형
'DB/MySQL' 카테고리의 다른 글
  • MySQL Full Text (with QueryDsl)
  • 클러스터링 인덱스
  • B-Tree 인덱스 2편
  • B-TREE 인덱스 1편
Debin
Debin
공부 기록을 남기며 게시글 리팩토링을 진행하는 블로그입니다.
  • Debin
    리팩토링하는 블로그
    Debin
  • 전체
    오늘
    어제
    • 분류 전체보기
      • DB
        • DB 기초
        • MySQL
        • SQL 튜닝
      • OS
      • Network
      • Git
      • 디지털콘텐츠기획
      • 소프트웨어공학
      • 코딩테스트
        • 프로그래머스
        • 백준
        • 인프런
      • 공부 일지
      • 독서
        • 클린코드
        • 일상 속 사물이 알려주는 웹 API 디자인
        • 토비의 스프링
        • 객체지향의 사실과 오해
        • 자바 잘 읽는 법
      • 기록 및 회고
      • Cloud
        • AWS
      • 개발
        • Java
        • Spring Core
        • Spring MVC
        • Spring DB
        • Spring Boot
        • Spring Security
        • Spring Batch
        • JPA
        • Test
        • Android
      • 대외활동
        • UMC SERVER
        • 카엔프 SW 아카데미
      • 프로젝트
      • Docker
      • Gradle
      • ELK
      • 실무 이야기
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • 깃허브
  • 공지사항

    • 본인 깃허브입니다!
  • 인기 글

  • 태그

    AOP
    JPA
    컨테이너
    트랜잭션
    docker
    spring boot
    인덱스
    container
    객체지향
    스프링 부트
    스프링
    ORM
    spring mvc
    redis
    운영체제
    test
    spring
    토비의 스프링
    SQL
    Java
    코딩 #개발자 #노마드북클럽 #노개북
    innodb
    프록시
    데이터베이스
    도커
    리눅스
    AWS
    mysql
    자바
    객체
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
Debin
InnoDB가 Phantom Read를 피하는 법
상단으로

티스토리툴바