InnoDB 스토리지 엔진은 MySQL에서 제공하는 잠금과는 별개로 스토리지 엔진 내부에 레코드 기반의 잠금 방식을 탑재하고 있다.
최근 버전에서는 InnoDB의 트랜잭션과 잠금, 그리고 잠금 대기 중인 트랜잭션의 목록을 조회할 수 있는 방법이 도입됐다.
MySQL 서버의 information_schema 데이터베이스에 존재하는 INNODB_TRX, INNODB_LOCKS, INNODB_LOCK_WAITS라는 테이블을 조인해서 조회하면 현재 어떤 트랜잭션이 잠금을 대기하고 있고 해당 잠금을 어느 트랜잭션이 가지고 있는지 확인할 수 있으며, 장시간 잠금을 가지고 있는 클라이언트를 찾아서 종료시킬 수 있다.
InnoDB 스토리지 엔진은 레코드 기반의 잠금 기능을 제공하며, 잠금 정보가 상당히 작은 공간으로 관리되기 때문에 레코드 락이 페이지 락으로, 또는 테이블 락으로 레벨업되는 경우는 없다.
레코드 락
레코드 자체만을 잠근다.
다른 사용 DBMS의 레코드 락과 동일한 역할을 한다.
한 가지 중요한 차이점은 InnoDB 스토리지 안젠은 레코드 자체가 아니라 인덱스의 레코드를 잠근다는 점이다.
인덱스가 하나도 없는 테이블이더라도 내부적으로 자동 생성된 클러스터 인덱스를 이용해 잠금을 설정한다.
보조 인덱스를 이용한 변경 작업은 이어서 설명할 넥스트 키 락 또는 갭 락을 사용하지만, 프라이머리 키 또는 유니크 인덱스에 의한 변경 작업에서는 갭에 대해서는 잠그지 않고 레코드 자체에 대해서만 락을 건다.
갭 락
갭 락은 레코드 자체가 아니라 레코드와 바로 인접한 레코드 사이의 간격만을 잠그는 것을 의미한다.
레코드와 레코드 사이의 간격에 새로운 레코드가 생성되는 것을 제어한다.
넥스트 키 락
레코드 락과 갭 락을 합친 잠금
갭 락은 그 자체를 사용하기보다는 넥스트 키 락의 일부로 자주 사용한다.
넥스트 키 락은 바이너리 로그에 기록되는 쿼리가 레플리카 서버에서 실행될 떄 소스 서버에서 만들어 낸 결과와 동일한 결과를 만들어내도록 보장하는 것이 주목적이다.
자동 증가 락
AURO_INCREMENT 칼럼이 동시에 여러 레코드가 INSERT 되는 경우, 저장되는 각 레코드는 중복되지 않고 저장된 순서대로 증가하는 일련번호 값을 가져야 한다.
이를 위해 내부적으로 AUTO_INCREMENT 락이라고 하는 테이블 수준의 잠금을 사용한다.
AUTO_INCREMENT 락은 INSERT와 REPLACE 쿼리 문장과 같이 새로운 레코드를 저장하는 쿼리에서만 필요하며, UPDATE나 DELETE 등의 쿼리에는 걸리지 않는다.
AUTO_INCREMENT 락은 명시적으로 획득하고 해제하는 방법은 없다.
AUTO_INCREMENT 락은 아주 짧은 시간 동안 걸렸다가 해제되는 잠금이라서 대부분의 경우 문제가 되지 않는다.
MySQL 5.1 이상부터는 자동 증가 락을 사용하지 않고 innodb_autoinc_lock_mod라는 시스템 변수를 이용해 자동 증가 락의 작동 방식을 변경할 수 있다.
innodb_autoinc_lock_mod=0: 모든 INSERT 문장에 자동 증가 락을 사용한다.
innodb_autoinc_lock_mod=1: 자동 증가 락을 사용하지 않고 훨씬 가볍고 빠른 래치(뮤텍스)를 이용해 처리한다. 하지만 INSERT ... SELECT 같이 MySQL 서버가 INSERT 되는 건수를 예측할 수 없을 때는 자동 증가 락을 사용한다. 이때 INSERT 문장이 완료되기 전까지 자동 증가 락은 해제되지 않기 때문에 다른 커넥션에서는 INSERT를 실행하지 못하고 대기하게 된다.
innodb_autoinc_lock_mod=2: 무조건 경량화된 래치(뮤텍스)를 사용한다. 하지만 이 설정에서는 하나의 INSERT 문장으로 INSERT 되는 레코드라고 하더라도 연속된 자동 증가 값을 보장하지 못한다. 또한, STATEMENT 포맷의 바이너리 로그를 사용하는 복제에서는 소스 서버와 레플리카 서버의 자동 증가 값이 달라질 수도 있기 떄문에 주의해야 한다.
MySQL 5.7 까지는 innodb_autoinc_lock_mod의 기본값이 1이었지만, MySQL 8.0 버전부터는 바이너리 로그 포맷이 STATEMENT가 아니라 ROW 포맷이 기본값이 되어서 innodb_autoinc_lock_mod의 기본값이 2로 바뀌었다.
자동 증가 값이 한 번 증가하면 절대 줄어들지 않는 이유가 AUTO_INCREMENT 잠금을 최소화하기 위해서다. 설령 INSERT 쿼리가 실패했더라도 한 번 증가된 AUTO_INCREMENT 값은 다시 줄어들지 않고 그대로 남는다.