- Shared and Exlusive Locks
- Intention Locks
- Record Locks
- Gap Locks
- Next-Key Locs
- Insert Intention Locks
- Predicate Locks for Spatial Indexes
Shared Lock과 Exclusive Lock의 두 가지 잠금 유형은 표준 행 수준의 잠금을 구현한다.
Shared Lock은 잠금을 보유한 트랜잭션이 행을 읽을 수 있도록 허용한다.
Exclusive Lock은 잠금을 보유한 트랜잭션이 행을 업데이트하거나 삭제할 수 있도록 허용한다.
공유 잠금예시로 트랜잭션 t1이 r행에게 공유 잠금을 보유하고 있을 때, 일부 개별 트랜잭션 t2의 행 r에 대한 잠금을 요청하는 경우 t2의 공유 잠금은 즉시 승인 되며, 결과적으로 t1 t2 모두 r에 대한 공유 잠금을 보유하게 된다. t2의 베타적 잠금은 즉시 승인될 수 없다.
배타적 잠금 예시로는 트랜잭션 t1이 행 r에 대해 배타적으로 보유하고 있을 때, 다른 트랜잭션 t2가 행 r에 대해 두 가지 유형의 잠금(공유, 배타적)을 요청해도 즉시 승인할 수 없다. 대신 트랜잭션 t2는 트랜잭션 t1이 행 r에 대해 잠금을 해제할 때 까지 기다려야한다.
행 잠금과 테이블 잠금이 공존할 수 있는 다중 세분성 잠금을 지원한다.
이 말이 무슨 말이냐면, 예를 들어서 LOCK TABLES ... WRITE 문은 지정된 테이블에 베타적 잠금을 사용한다. 여러 세분화 수준에서 잠그는 것을 실용적으로 만들기 위해서 Intention Lock을 innodb에서 지원하는 것이다.
Intention 잠금은 테이블의 행에 대해 나중에 트랜잭션에 필요한 잠금 유형(공유, 배타적)을 나타내는 테이블 수준의 잠금이다. Intention 잠금에는 두 가지 유형이 있다.
- 의도적 공유 잠금(IS): 트랜잭션이 테이블 개별 행에 공유 잠금을 설정하려는 의도를 나타낸다.
- 의도적 독점 잠금(IX): 트랜잭션이 테이블 개별 행에 배타적 잠금을 설정하려는 의도를 나타낸다.
테이블 수준 잠금 유형 호환성은 다음 표를 통해 확인할 수 있다.
요청하는 트랜잭션이 기존 잠금과 호환되는 경우 잠금이 부여되지만, 기존 잠금과 충돌하는 경우에는 잠금이 부여되지 않는다. 트랜잭션은 충돌하는 기존 잠금이 해제될 때까지 대기한다. 잠금 요청이 기존 잠금과 충돌하여 교착 상태가 발생해, 잠금을 부여할 수 없는 경우 오류가 발생한다.
Intention 잠금은 전체 테이블 요청(ex LOCK TABLES ... WRITE
)를 제외하고는 아무것도 차단하지 않는다. 즉, Intention 잠금의 주요 목적은 누군가 행을 잠그고 있거나 테이블의 행을 잠그려고 한다는 것을 표시하는 것이다.
예시로 표에서 IX, IX 사이에서는 Compatible이기에, 하나의 테이블에 트랜잭션 t1이 IX를 가지고 있게 되면, 트랜잭션 T2는 IX를 가질 수 없다. 그러나 한 행에 대해 트랜잭션 t1이 X를 가지면 T2는 X를 가질 수 없다
Record Lock은 인덱스 레코드에 대한 잠금이다. 간단하게 진짜 레코드에 대한 잠금이다(네)
예시로 SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE;
쿼리문은 다른 트랜잭션이 t.c1의 값이 10인 행을 삽입, 업데이트 또는 삭제하지 못하게 한다.
레코드 잠금은 테이블이 인덱스 없이 정의된 경우에도 항상 인덱스 레코드를 잠근다. 이러한 경우 innodb는 숨겨진 clustered index를 생성하고 이 인덱스를 레코드 잠금에 사용한다.
Gap Lock은 인덱스 레코드 사이의 간격에 대한 잠금 또는, 첫 번째 혹은 마지막 인덱스 레코드 앞뒤의 간격에 대한 잠금이다.
예를 들어서 SELECT c1 FROM t WHERE BETWEEN 10 AND 20 FOR UPDATE;
범위의 모든 기존 값 사이의 간격이 잠겨있으므로 열에 이미 해당 값이 있든 없든 다른 트랜잭션이 t.c1 열에 15라는 값을 삽입하지 못하도록 한다.
Gap락은 단일 인덱스 값, 여러 인덱스 값에 걸쳐 있을 수도 있고 없을 수도 있다. 갭락은 성능과 동시성 사이의 절충안의 일부라고 생각한다.
서로 다른 트랜잭션이 갭에 충돌하는 잠금을 보유할 수 있는데, 예를 들어 트랜잭션 t1은 하나의 갭에 대해 share gap lock을 트랜잭션 t2는 동일한 갭에 exlusive gap lock을 유지할 수 있다. 충도하는 갭 락이 허용되는 이유는 하나의 레코드가 인덱스에서 제거될 경우, 다른 트랜잭션이 해당 레코드에 보유한 갭 잠금을 병합해야하기 때문이다.
즉, innodb의 gap lock 기능은 순수 억제형으로, 다른 트랜잭션이 갭에 삽입되는 것을 방지하기 위하는 것이 유일한 목적이라고 볼 수 있다.
Next Key Lock은 인덱스 레코드에 대한 Record Lock과 인덱스 레코드 앞의 Gap애 대한 Gap Lock을 조합한 형태다.
innodb는 테이블 인덱스를 검색하거나 스캔할 때 마주치는 인덱스 레코드에 공유 또는 배타적 락을 설정하는 방식으로 행 수준의 잠금을 수행한다. 따라서 행 수준 잠금은 실제로는 인덱스 레코드 잠금이다.
인덱스 레코드에 대한 Next-Key Lock은 해당 인덱스 레코드 앞의 Gap에도 영향을 미친다. 한 세션이 인덱스 레코드 R에 Share or Exclusive Lock을 설정한 경우, 다른 세션은 인덱스 순서에 R 바로 앞의 갭에 새 인덱스 레코드를 삽입할 수 없다.
예시로 인덱스에 값이 10, 11, 13, 29이 포함되어있다고 할때 이 인덱스에 대해 가능한 다음 키의 잠금은 다음 간격을 포함하며, 여기서 둥근 대괄호는 간격 끝점을 제외하고 대괄호 끝점을 포함한다.
(negative infinity, 10]
(10, 11]
(11, 13]
(13, 20]
(20, positive infinity)
마지막 간격에서 Next Key Lock은 인덱스에서 가장 큰 값과 실제 인덱스의 어떤 값보다 높은 값을 가진 최상위 의사 레코드 사이의 간격을 잠근다. 최상위 레코드는 실제 인덱스 레코드가 아니므로 사실상 이 Next Key Lock은 가장 인덱스에서 큰 값 다은 가격만 잠금된다.
Insert Intention Lock은 행 삽입 전에 INSERT 연산에 의해 설정되는 일종의 갭 락이다.
동일한 인덱스 갭에 삽입하는 여러 트랜잭션이 갭 내의 동일한 위치에 삽입하지 않는 경우 서로 기다릴 푤어가 없도록 삽입 의도를 알리게 된다.
예를 들어 값이 4와 7인 인덱스 레코드가 있다고 가정해보자, 각각 5와 6의 값을 삽입하려는 별도의 트랜잭션은 삽입된 행에 대한 독점 잠금을 얻기 전에 각각의 삽입 의도 잠금으로 4와 7사이의 간격을 잠그지만 행이 충돌하지 않으므로 서로를 차단하지 않는다.
다음 예시 하나를 더 보여주면 삽입된 레코드에 대해 배타적 락을 얻기 전에 Insert Intention Lcok을 취하는 트랜잭션을 보여준다. 클라이언트1은 두 개의 인스턴스 레코드(90. 102)가 포함된 테이블을 생성 후 아이디가 100보다 큰 인덱스 레코드에 배타적 락을 설정하는 트랜잭션을 시작한다. 이 배타적 락은 102번 레코드 앞에 갭 잠금에 포함된다. 클라이언트2는 갭에 레코드를 삽입하는 트랜잭션을 시작하는데, 트랜잭션은 배타적 락을 얻기 위해 기다리는 동안 Insert Intention Lock 을 취한다.
// A
mysql> CREATE TABLE child (id int(11) NOT NULL, PRIMARY KEY(id)) ENGINE=InnoDB;
mysql> INSERT INTO child (id) values (90),(102);
mysql> START TRANSACTION;
mysql> SELECT * FROM child WHERE id > 100 FOR UPDATE;
+-----+
| id |
+-----+
| 102 |
+-----+
// B
mysql> START TRANSACTION;
mysql> INSERT INTO child (id) VALUES (101);
AUTO-INC Lock은 AUTO_INCREMENT 열에 있는 테이블에 삽입하는 트랜잭션이 취하는 특수한 테이블 수준의 잠금이다.
예시로 한 트랜잭션이 테이블에 값을 삽입하는 경우에 다른 트랜잭션은 해당 테이블에 삽입을 수행하기 위해 기다린다. 첫 번째 트랜잭션에 의해 삽입된 행은 연속적인 기본 키 값을 받게 된다.
innodb_autoinc_lock_mode
시스템 변수는 자동 증가 잠금에 사용되는 알고리즘을 제어한다. 이 변수를 사용하면 예측 가능한 자동 증가 값의 시퀀스 삽입과 작업의 최대 동시성 사이에서 절충하는 방법을 선택할 수 있다.
innodb는 공간 데이터가 포함된 열의 공간 인덱싱을 지원한다.
공간 인덱스와 관련된 연산에 대한 잠금을 처리하기 위해서 next key lock은 REPEATABLE READ
또는 SERIALIZABLE
수준에서 지원하는데 적합하지 않다. 다차원 데이터는 절대적인 순서 개념이 없기 때문에 어떤것이 넥스트인지 명확한 기준이 없기 때문이다.
SPATIAL 인덱스가 있는 테이블에 대한 격리 수준을 지원하기 위해서 innodb는 Predicate Lock을 사용한다. SPATIAL 인덱스에는 최소 바운딩 사각형 (MBR) 값이 포함되어 있기 때문에 innodb는 쿼리에 사용되는 MBR 값이 predicate lock을 설정해 인덱스에서 일관된 읽기를 시행한다. 다른 트랜잭션은 쿼리 조건과 일치하는 행을 삽입하거나 수정할 수 없다.