ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 5장 - 트랜잭션과 잠금
    CS/Real MySQL 8.0 요약 2023. 10. 26. 00:01

    트랜잭션이란?

    데이터 정합성을 보장하기 위해 논리적인 작업을 묶어 일부만 적용되는 현상을 발생하지 않도록 만들어주는 기능이다.

     

    잠금이란?

    잠금과 트랜잭션은 비슷한 개념 같지만 잠금은 동시성을 제어하기 위한 기능이다.

    하나의 데이터를 여러 커넥션이 동시에 변경하지 못하게 막는 역할을 수행한다.

     

    격리 수준이란?

    하나의 트랜잭션 내에서 또는 여러 트랜잭션 강의 작업 내용을 어떻게 공유하고 차단할지 결정하는 레벨을 의미한다.

     

     

    MySQL에서 트랜잭션

    MyISAM이나 Memory 스토리지 엔진은 트랜잭션을 지원하지 않고 InnoDB부터 트랜잭션을 지원한다.

    MyISAM의 경우에는 Partial Update가 발생하여 데이터 정합을 맞추기 까다롭다.

     

    트랜잭션의 범위는 최소화해야 커넥션풀을 점유하는 시간이 줄어들고 부하를 줄일 수 있다. (외부 호출과 같은 부분을 제거해야 한다)

     

    MySQL에서 잠금

    스토리지 엔진 레벨 그리고 MySQL 엔진 레벨에서 잠금을 지원한다.

     

    MySQL 엔진 레벨의 잠금은 모든 스토리지 엔진에 영향을 미친다.

    스토리지 엔진 레벨 잠금은 스토리지 엔진 간 상호 영향을 미치지 않는다.

     

    MySQL 엔진 레벨 잠금으로는 백업락, 테이블 락, 메타데이터 락, 네임드 락 등이 있습니다.

    • 메타데이터 락 : 테이블, 뷰 이름이나 구조를 변경하는 경우에 획득하는 잠금
    • 네임드 락 : 분산 시스템에서 임의의 문자열에 대해 잠금을 설정하여 동시성을 보장
    • 테이블 락 :테이블을 명시적으로 잠금 (성능에 영향이 커서 거의 사용할 필요 없음)

     

    InnoDB 스토리지 엔진 레벨 잠금으로는 레코드 락, 갭락, 넥스트 키 락, 자동 증가 락 등이 있습니다.

    • 레코드 락 : 레코드 자체가 아닌 인덱스의 레코드를 잠금을 수행합니다. 특정 레코드를 잠가 다른 트랜잭션이 동시에 동일한 레코드를 수정하거나 잠그지 못하도록 합니다. (예를 들어 select... for update 같은 쿼리 수행 시)
    • 갭 락 : 레코드와 바로 인접한 레코드 사이의 간격을 잠가 새로운 레코드가 생성되는 것을 제어합니다. (트랜잭션 A가 나이가 30~40 사이의 모든 사용자 레코드를 선택하는 쿼리를 실행하는 경우 B가 나이가 35인 새로운 사용자를 삽입하려고 하는 경우를 방지하여 트랜잭션 A가 일괄된 결과를 읽도록 제공)
    • 넥스트 키 락 : 레코드 락과 갭락을 합쳐 놓은 형태 (바이너리 로그 포맷을 ROW형태로 바꾸는 것이 좋음)
    • 자동 증가 락 : AUTO_INCREMENT시 중복되지 않고 지정된 순서로 증가되는 일련번호를 제공하기 위해 테이블 수준의 잠금을 사용합니다. 명시적으로 획득하고 해제하는 방법은 없으며, 대부분 짧은 시간 걸렸다가 해제되어 문제가 되지 않습니다.

     

    인덱스와 잠금

    레코드 락의 경우 인덱스를 잠그는 방식으로 처리됩니다.

    update 구문이 실행되면 1건의 레코드가 업데이트될 것입니다.

    하지만 이 업데이트를 위해 몇 개의 레코드에 락을 걸어야 할까요?

    last_name 칼럼에는 인덱스가 없기 때문에 253건의 레코드가 모두 잠기게 됩니다.

    UPDATE시 적절한 인덱스가 준비되어 있지 않다면 다른 클라이언트는 대기하게 됩니다.

    또한 인덱스가 하나도 없다면 테이블을 풀 스캔 하면서 update 작업을 수행하게 됩니다..

     

     

    잠금 모니터링

    innodb_trx, innodb_locks_innodb_lock_waits라는 테이블을 활용하거나 data_locks, data_lock_waits테이블을 통해 잠금과 잠금 대기 순서를 확인할 수 있습니다.

     

    MySQL의 격리 수준

    아래로 내려갈수록 데이터 격리정도가 높아지며 성능이 떨어집니다.

    하지만 SERIALIZABLE이 아닌 이상 크게 성능의 개선이나 저하는 발생하지 않습니다.

     

    READ UNCOMMITTED

    커밋되지 않은 변경건도 다른 트랜잭션에서 볼 수 있습니다.

     

    READ COMMITTED

    다른 트랜잭션에서 변경이 발생해도 언두 로그의 데이터를 반환하여 커밋되지 않은 내용은 보지 않습니다.

     

    REPEATABLE READ

    InnoDB 스토리지 엔진에서 기본으로 사용되는 격리 수준입니다.

    데이터를 읽고 변경 후 커밋이 발생하더라도 커밋되고 변경된 데이터를 보지 않고 MVCC를 활용하여 언두 영역에 백업된 이전 데이터를 이용하여 동일 트랜잭션 내에서는 동일한 결과를 보여줄 수 있게 보장합니다.

     

    사실 READ COMMITTED도 동일한 원리를 이용!

     

    SERIALIZABLE

    순수 select 작업도 잠금을 획득해야 합니다.

    일반적인 DBMS에서 발생하는 팬텀리드도 발생하지 않지만 InnoDB의 경우 갭락과 넥스트 키 락 덕분에 REPEATABLE READ에서도 팬텀디르가 발생하지 않기 때문에 이를 사용할 필요는 없습니다.

    댓글

Designed by Tistory.