본문 바로가기

데이터베이스

[Real MySQL 8.0] 5장. 트랜잭션과 잠금

  • 잠금(Lock)은 동시성을 제어하기 위한 기능 
  • 트랜잭션은 데이터의 정합성을 보장하기 위한 기능
  • 격리 수준은 하나의 트랜잭션 내에서 또는 여러 트랜잭션 간의 작업 내용을 어떻게 공유하고 차단할 것인지 결정하는 레벨

트랜잭션

  • 하나의 논리적인 작업 셋에 하나의 쿼리가 있든 두 개 이상의 쿼리가 있든 관계없이 논리적인 작업 셋 자체가 커밋되거나 롤백됨을 보장해주는 것

MySQL 엔진의 잠금

글로벌 락

  • FLUSH TABLES WITH READ LOCK 명령으로 획득 가능
  • 다른 세션에서 SELECT를 제외한 대부분의 DDL 문장이나 DML 문장을 실행하는 경우 글로벌 락이 해제될 때까지 해당 문장이 대기 상태로 남음
  • 실행과 동시에 MySQL 서버에 존재하는 모든 테이블을 닫고 잠금을 검
  • mysqldump같은 백업 프로그램이 우리가 알지 못하는 사이에 이 명령을 내부적으로 실행하고 백업할 때도 있음
  • InnoDB 스토리지 엔진은 트랜잭션을 지원하기 때문에 일관된 데이터 상태를 위해 모든 데이터 변경 작업을 멈출 필요는 없음
  • MySQL 8.0부터는 백업 락이 도입됨
    • 백업 락은 일반적인 테이블의 데이터 변경은 허용

테이블 락

  • 개별 테이블 단위로 설정되는 잠금
  • 명시적
    • LOCK TABLES table_name [READ | WRITE] (테이블 잠금)
    • UNLOCK TABLES (잠금 해제)
  • 묵시적
    • InnoDB 스토리지 엔진에서는 다른 MyISAM이나 MEMORY 테이블과 다르게 스토리지 엔진 차원에서 레코드 기반의 잠금을 제공하기 때문에 단순 데이터 변경 쿼리로 인해 묵시적인 테이블 락이 설정되지는 않음 
    • InnoDB 테이블에도 테이블 락이 설정되지만 대부분의 DML 쿼리에서는 무시되고 DDL 쿼리의 경우에만 영향을 미침

네임드 락

  • GET_LOCK() 함수를 이용해 임의의 문자열에 대해 잠금을 설정할 수 있음
  • 단순리 사용자가 지정한 문자열에 대해 왹득하고 반납하는 잠금
  • 많은 레코드에 대해서 복잡한 요건으로 레코드를 변경하는 트랜잭션에 유용하게 사용될 수 있음
  • 배치 프로그램처럼 한번에 많은 레코드를 변경하는 쿼리는 자주 데드락의 원인이 되는데, 이를 동일 데이터를 변경하거나 참조하는 프로그램끼리 분류해 네임드 락을 걸어 해결할 수 있음

메타데이터 락

  • 데이터베이스 객체(테이블이나 뷰)의 이름이나 구조를 변경하는 경우 자동으로 획득하는 잠금
  • RENAME TABLE a to b

InnoDB 스토리지 엔진 잠금

  • 레코드 기반의 잠금 기능을 제공
  • 레코드와 레코드 사이의 간격을 잠그는 갭 락이라는 것도 존재

레코드 락

  • 레코드 자체가 아니라 인덱스의 레코드를 잠금
  • 인덱스가 없는 테이블이더라도 내부적으로 자동 생성된 클러스터 인덱스를 이용해 잠금
  • PK 또는 유니크 인덱스에 의한 변경 작업에서는 레코드 락 사용

갭 락

  • 레코드와 레코드 사이의 간격에 새로운 레코드가 생성되는 것을 제어
  • 넥스트 키 락의 일부로 자주 사용됨

넥스트 키 락

  • 레코드 락과 갭 락을 합쳐놓은 형태
  • STATEMENT 포맷의 바이너리 로그를 사용하는 MySQL 서버에서는 REPEATABLE READ 격리 수준을 사용해야 함
  • 바이너리 로그에 기록되는 쿼리가 레플리카 서버에 실행될 때 소스 서버에서 만들어 낸 결과와 동일한 결과를 만들어 내도록 보장하는 것이 목적
  • 넥스트 키 락과 갭 락으로 인해 데드락이 발생하거나 다른 트랜잭션을 기다리게 만드는 일이 자주 발생
  • 바이너리 로그 포맷을 ROW 형태로 바꿔서 넥스트 키 락이나 갭 락을 줄이는 것이 좋음

자동 증가 락

  • AUTO_INCREMENT 칼럼이 사용된 테이블에 동시에 여러 레코드가 INSERT 되는 경우, 저장되는 각 레코드는 중복되지 않고 저장된 순서대로 증가하는 일련번호 값을 가져야 함
  • InnoDB 스토리지 엔진에서는 이를 위해 내부적으로 AUTO_INCREMENT 락이라고 하는 테이블 수준의 잠금을 사용
  • 자동 증가 값이 증가하면 절대 줄어들지 않는 이유가 이 잠금을 최소화하기 위해

더 읽어보면 좋은 글