Gap Lock (MySQL)

Gap Lock(갭 락)은 MySQL의 InnoDB 스토리지 엔진에서 사용되는 잠금 메커니즘 중 하나로, 특히 REPEATABLE READ 및 SERIALIZABLE 격리 수준에서 레코드 사이의 “갭”에 대해 잠금을 설정합니다. 이는 팬텀 리드(Phantom Read)를 방지하고 일관된 데이터 읽기 및 쓰기를 보장하기 위해 사용됩니다. Gap Lock의

Overlay Image Overlay Image
« Back to Glossary Index

Gap Lock(갭 락)은 MySQL의 InnoDB 스토리지 엔진에서 사용되는 잠금 메커니즘 중 하나로, 특히 REPEATABLE READSERIALIZABLE 격리 수준에서 레코드 사이의 “갭”에 대해 잠금을 설정합니다. 이는 팬텀 리드(Phantom Read)를 방지하고 일관된 데이터 읽기 및 쓰기를 보장하기 위해 사용됩니다.

Gap Lock의 필요성

갭 락은 특정 쿼리에서 레코드 자체뿐만 아니라 레코드 사이의 공간(갭)에 대해서도 잠금을 걸어야 할 때 사용됩니다. 이는 다른 트랜잭션이 해당 갭에 새로운 레코드를 삽입하는 것을 방지하여 데이터의 일관성을 유지합니다.

예를 들어, 어떤 트랜잭션이 특정 범위의 레코드를 조회하고 있다면, 다른 트랜잭션이 그 범위 내에 새로운 레코드를 삽입하는 것을 막아야 팬텀 리드를 방지할 수 있습니다.

Gap Lock의 동작 방식

갭 락은 인덱스 레코드 사이의 공간에 대해 잠금을 설정합니다. 이는 인덱스가 없는 테이블에서는 적용되지 않으며, 반드시 인덱스를 통해 접근하는 경우에만 발생합니다.

예제

테이블 생성 및 데이터 삽입

우선, 예제를 위해 간단한 테이블을 생성하고 데이터를 삽입합니다.

CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(50)
);

INSERT INTO users (id, name) VALUES
(1, 'Alice'),
(5, 'Bob'),
(10, 'Charlie');

트랜잭션 A: 갭 락 획득

트랜잭션 A에서 다음과 같은 쿼리를 실행합니다.

-- 트랜잭션 A 시작
START TRANSACTION;

-- id가 5보다 큰 레코드를 조회
SELECT * FROM users WHERE id > 5 FOR UPDATE;

이 쿼리는 id > 5인 레코드들을 잠금합니다. 그러나 여기서 중요한 것은 FOR UPDATE가 사용되었기 때문에 InnoDB는 해당 범위에 대해 갭 락을 설정합니다. 즉, id가 5와 10 사이인 값에 대해 새로운 레코드가 삽입되는 것을 막습니다.

트랜잭션 B: 갭에 레코드 삽입 시도

다른 세션에서 트랜잭션 B를 시작하고, 갭에 새로운 레코드를 삽입하려고 합니다.

-- 트랜잭션 B 시작
START TRANSACTION;

-- id가 7인 레코드 삽입 시도
INSERT INTO users (id, name) VALUES (7, 'Dave');

이 경우, 트랜잭션 B는 트랜잭션 A가 보유한 갭 락 때문에 블록되거나 대기 상태에 들어갑니다. 트랜잭션 A가 커밋되거나 롤백될 때까지 트랜잭션 B는 진행되지 않습니다.

트랜잭션 A 커밋 또는 롤백

트랜잭션 A를 커밋하거나 롤백하면 트랜잭션 B는 다음과 같이 진행됩니다.

-- 트랜잭션 A 커밋
COMMIT;

이후 트랜잭션 B의 INSERT 쿼리는 성공하거나 실패하게 됩니다. 만약 트랜잭션 A가 커밋되었다면, 갭 락이 해제되어 트랜잭션 B의 INSERT가 성공합니다. 그러나 그 사이에 다른 제약 조건이나 락이 발생할 수 있으므로 상황에 따라 다를 수 있습니다.

Gap Lock이 발생하는 상황

  • 범위 조건이 있는 SELECT … FOR UPDATE 또는 SELECT … LOCK IN SHARE MODE 쿼리
  • DELETE 또는 UPDATE 쿼리에서 범위 조건이 사용될 때

격리 수준과의 관계

갭 락은 기본적으로 REPEATABLE READ 격리 수준에서 활성화됩니다. READ COMMITTED 격리 수준에서는 갭 락이 발생하지 않습니다. 이는 트랜잭션 격리 수준에 따라 팬텀 리드 방지 여부가 달라지기 때문입니다.

  • READ COMMITTED: 갭 락 사용 안 함, 팬텀 리드 허용
  • REPEATABLE READ: 갭 락 사용, 팬텀 리드 방지
  • SERIALIZABLE: 갭 락 사용, 가장 엄격한 격리 수준

Gap Lock 회피 방법

만약 갭 락으로 인한 성능 저하나 교착 상태가 우려된다면, 다음과 같은 방법을 고려할 수 있습니다.

  • 격리 수준을 READ COMMITTED로 변경: 그러나 이 경우 팬텀 리드가 발생할 수 있습니다.
  • 인덱스 설계를 개선하여 잠금 범위를 최소화
  • 적절한 락 힌트 사용: LOCK IN SHARE MODE 대신 FOR UPDATE 사용 여부 등을 검토

주의 사항

  • 인덱스가 없는 경우 갭 락은 발생하지 않습니다.
  • 갭 락은 MySQL의 InnoDB 엔진에서만 지원됩니다.
  • 갭 락은 교착 상태를 유발할 수 있으므로 주의해야 합니다.

결론

갭 락은 트랜잭션 간의 일관성을 유지하고 팬텀 리드를 방지하기 위한 중요한 메커니즘입니다. 그러나 불필요한 갭 락은 성능 저하나 교착 상태를 유발할 수 있으므로, 애플리케이션의 특성과 요구 사항에 맞게 적절히 사용해야 합니다.

« Back to Glossary Index