Lock

3 분 소요

Locking은 트랜잭션의 실행 순서를 강제로 제어하여 직렬 가능한 스케줄이 되도록 보장하는 방법이다.

Locking

MySQL 8.0 Reference Manual 15.7.1 InnoDB Locking 번역

Shared and Exclusive Locks

InnoDB는 두가지 종류의 일반적인 row-level locking을 구현합니다.

  • shared lock
    Shared lock은 lock을 건 트랜잭션이 row를 읽을 수 있도록 허용합니다.

  • exclusive lock
    Exclusive lock은 lock을 건 트랜잭션이 row를 수정/삭제할 수 있도록 허용합니다.

트랜잭션 T1이 row r에 shared lock을 걸은 상황에서, 다른 트랜잭션 T2는 아래와 같이 처리됩니다.

  • T2가 r에 요청한 shared lock은 즉시 승인됩니다. T1, T2 모두 row r에 shared lock을 걸고 있습니다.

  • T2가 r에 요청한 exclusive lock은 즉시 승인되지 못합니다.

Record Locks

Record lock은 index record에 걸리는 lock입니다. 예를 들어, SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE;t.c1의 값이 10인 row들을 다른 트랜잭션들이 생성, 수정, 삭제하지 못하도록 막습니다.

Record locks는 table에 index가 정의되어있지 않더라도, 항상 index에 lock을 적용합니다. 그런 경우에 InnoDB는 숨겨진 clustered index를 생성하고, 이를 record locking에 사용합니다.

Gap Locks

Gap lock은 두개의 index record 사이의 gap(공백) 혹은, 첫번째 index record 이전의 gap, 또는 마지막 index record 이후의 gap에 걸리는 lock 입니다. 예를 들어, SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR UPDATE;t.c1이 15인 row를 insert하지 못하게 막습니다. t.c1이 15인 row가 존재하지 않음에도 막힐 것입니다. 범위 내(BETWEEN 10 and 20) 모든 값에 해당하는 gap이 lock 되었기 때문입니다.

Gap lock은 성능과 일관성 사이의 tradeoff입니다. Gap lock은 몇개의 트랜잭션 isolation level에 사용되고, 나머지에서는 사용되지 않습니다.

Gap lock은 unique row를 찾기 위해 unique index를 사용하여 row를 lock하는 상황에서는 필요하지 않습니다.(검색 조건에 multiple-column unique index중 몇개만 포함되는 경우는 예외입니다; 해당 경우에는 gap locking이 일어납니다.) 예를 들어, id 컬럼이 unique index를 가지고 있다면, 아래의 쿼리는 id가 100인 row에만 index-record lock를 사용합니다. 다른 세션들이 전후의 gap에 row를 삽입하는 것을 상관하지 않습니다.

1
SELECT * FROM child WHERE id = 100;

만약 id가 index되지 않았거나 nonunique index를 가진다면, 위 쿼리는 선행 gap을 lock할 것입니다.

서로 다른 트랜잭션들이 한 gap에 경합하는 lock들을 가질 수 있습니다. 예를 들어, 트랜잭션 B가 exclusive gap lock를 걸고 있는 gap에 트랜잭션 A 또한 shared gap lock를 걸 수 있습니다. 이런 경합 상황을 허용하는 이유는, 만약 어떤 record가 index로부터 제거된다면, 해당 record에 서로 다른 트랜잭션들이 걸고 있던 gap lock들은 병합되어야 하기 때문입니다.

InnoDB의 gap lock은 완전히 억제되어있습니다. 즉, gap lock의 유일한 목적은 다른 트랜잭션이 gap에 insert하는 것을 막는 것입니다. Gap lock은 상호 존재할 수 있습니다. 하나의 트랜잭션이 건 gap lock은 다른 트랜잭션이 동일한 gap에 gap lock을 거는 것을 막지 않습니다. Gap lock에서는 shared lock과 exclusive lock에 차이가 없습니다. 이들은 서로 경합하지 않고 동일한 기능을 수행합니다.

Gap locking은 명시적으로 해제될 수 있습니다. 이는 트랜잭션 격리 수준을 READ COMMITTED로 변경할 때 일어납니다. 이 경우에, gap locking은 검색, 그리고 index scan에 있어서 해제되고, 외래키 제약 확인과 중복 키 검사에만 사용됩니다.

Next-Key Locks

Next-key lock은 index record의 record lock과, index record 이전의 gap의 gap lock의 혼합입니다.

InnoDB는 테이블 인덱스를 탐색 혹은 스캔할 때 만나는 index record들에 shared 혹은 exclusive lock를 적용함으로 row-level locking을 수행합니다. 이처럼 row-level lock들은 실제로 index-record lock 입니다. Index record의 next-key lock은 해당 index record 이전의 gap에도 영향을 줍니다. Next-key lock은 index-record lock 더하기 index record의 선행 gap에 걸리는 gap lock입니다. 만약 하나의 세션이 index의 record R에 shared 혹은 exclusive lock을 걸고있을 때, 다른 세션이 index 순서 중 R 이전의 gap에 즉시 새로운 index를 삽입하는 것은 불가능합니다.

요약

row-level locking 종류

  • shared lock
    • shared lock이 걸린 상태에서 다른 트랜잭션이 shared lock을 거는 것이 가능합니다.
    • shared lock이 걸린 상태에서 다른 트랜잭션이 exclusive lock을 거는 것은 불가능합니다.
  • exclusive lock
    • exclusive lock이 걸린 상태에서는 다른 트랜잭션이 shared lock, exclusive lock을 모두 걸 수 없습니다.

index lock

  • record lock
    • Record locks는 table에 index가 정의되어있지 않더라도, 항상 index에 lock을 적용합니다. 그런 경우에 InnoDB는 숨겨진 clustered index를 생성하고, 이를 record locking에 사용합니다.
  • gap lock
    • Gap lock은 두개의 index record 사이의 gap(공백) 혹은, 첫번째 index record 이전의 gap, 또는 마지막 index record 이후의 gap에 걸리는 lock 입니다.
  • next key lock
    • record lock 과 gap lock의 합성

댓글남기기