Gap Lock
Gap Lock이란
Gap Lock은 MySQL InnoDB에서 기존 레코드 자체가 아니라 인덱스 레코드 사이의 빈 구간을 잠그는 락이다.
예를 들어 인덱스 값이 10, 20, 30이라면 다음과 같은 구간을 생각할 수 있다.
(-∞, 10)(10, 20)(20, 30)(30, +∞)
Gap Lock은 이 구간에 새로운 값이 끼어드는 것을 막는다. 매뉴얼은 “their only purpose is to prevent other transactions from inserting to the gap”이라고 쓴다(다른 트랜잭션의 삽입을 막는 것이 유일한 목적이다).
왜 필요한가
주된 목적은 팬텀 리드를 막는 것이다. 범위 조건으로 읽은 결과가 트랜잭션 도중 달라지지 않게 하려면, 현재 존재하는 행만 잠그는 것으로는 부족할 수 있다. 중간에 새로운 행이 삽입되면 결과 집합이 바뀌기 때문이다.
Record Lock, Gap Lock, Next-Key Lock
Record Lock: 기존 레코드 자체 잠금Gap Lock: 레코드 사이 빈 구간 잠금Next-Key Lock: Record Lock + 그 레코드 앞쪽 Gap Lock
기본 격리 수준인 REPEATABLE READ에서 InnoDB는 검색과 인덱스 스캔에 Next-Key Lock을 사용하고, 이것으로 팬텀 행을 막는다(락의 종류와 대기).
언제 자주 보나
SELECT ... FOR UPDATESELECT ... LOCK IN SHARE MODE- 범위 조건이 있는
UPDATE,DELETE REPEATABLE READ격리 수준
인덱스가 매우 중요하다
Gap Lock은 어떤 인덱스를 타고 어떤 범위를 읽는지와 연결된다. 적절한 인덱스가 없으면 예상보다 훨씬 넓은 범위를 잠그는 것처럼 보일 수 있다.
그래서 락 문제를 볼 때는 SQL만 보지 말고 실행 계획과 인덱스 구성을 같이 봐야 한다.
실무에서 헷갈리는 상황
- 특정 행만 읽은 줄 알았는데 insert가 막힘
- 단건 조회라 생각했는데 실제론 범위 스캔이었음
- 격리 수준을 바꾸니 현상이 달라짐
이런 문제는 대부분 “레코드를 잠근 줄 알았는데 사실은 gap까지 잠겼다”로 해석할 수 있다. 세 번째 경우는 매뉴얼에 근거가 있다. READ COMMITTED에서는 검색과 인덱스 스캔의 gap locking이 꺼진다.
정리
Gap Lock은 기존 레코드를 보호하는 락이 아니라, 새로운 레코드가 끼어들어 읽기 결과가 흔들리는 것을 막는 락이다. 그래서 insert가 예상 밖에서 막히면 어떤 인덱스 범위를 읽었는지부터 확인한다.
댓글
아직 댓글이 없습니다