Real mysql 8.0 ch5~6

5_ 트랜잭션과 잠금

트랜잭션이 선택 사항인 MySQL 어떤 사용자는 트랜잭션을 상당히 골치 아픈 기능 쯤으로 생각한다.

  • 필수 요소라고 생각했는데 선택이고, 골치 아픈 기능이라고 생각하는 사람이 있다니, 어떤 부분에서 골치 아픈 기능이라 생각하는지 궁금하다.
  • 잠금과 트랜잭션은 비슷한 개념 같지만 목적이 다르다.
    • 잠금은 동시성을 제어하기 위한 기능.
    • 트랜잭션은 데이터의 정합성, 작업의 완전성을 보장하기 위한 기능.

트랜잭션

프로그램 코드에서 트랜잭션의 범위를 최소화하라. 트랜잭션에 묶는 범위에 단순 조회는 묶을 필요가 없다. 작업의 성격에 맞게 묶어야한다. 네트워크를 통해 원격 서버와 통신하는 등과 같은 작업은 어떻게 해서든 DBMS의 트랜잭션 내에서 제거하는 것이 좋다.

ORM에서는 트랜잭션을 어떻게 다루고 있을까?

  • 내부적으로 트랜잭션이 제공되고 데코레이터를 사용하지만, 필요에 따라 명시적으로 트랜잭션을 묶기도 한다.
    • @Transaction

잠금

잠금(lock)은 트랜잭션을 순차적으로 처리되도록 한다. 자동 발생되며 동일한 데이터를 동시에 엑세스할 수 있게 해준다.

락 에스컬레이션에 대비하는 방법은 트랜잭션을 작은 단위로 관리하는 것이다. InnoDB 스토리지 엔진은 잠금 정보가 상당히 작은 공간으로 관리되기 때문에 락 에스컬레이션의 경우는 없다.

레코드를 잠그느냐 인덱스를 잠그느냐는 상당히 크고 중요한 차이를 만들어 낸다. 레코드를 잠근다면 update시에 무수히 많은 레코드를 락을 걸어야하지만 인덱스를 잠그면 해당 인덱스에 대해서 레코드를 검색한다. 적절히 인덱스를 걸어두면 작업시에 락을 거는 대상이 줄어들게 된다. MySQL InnoDB에서 인덱스가 중요한 이유이다.

네임드 락

GET_LOCK() 함수를 이용해 단순히 사용자가 지정한 문자열(String)에 대해 획득하고 반납(해제)하는 잠금이다. 여러 클라이언트가 상호 동기화를 처리해야 할 때, 많은 레코드에 대해서 복잡한 요건으로 레코드를 변경하는 트랜잭션에 유용하다. 동일 데이터를 변경하거나 참조하는 프로그램끼지 분류해서 네임드 락을 걸고 쿼리를 실행하면 아주 간단히 해결할 수 있다.


격리 수준

격리 수준(isolation level)이란 여러 트랜잭션이 동시에 처리될 때 특정 트랜잭션이 다른 트랜잭션에서 변경하거나 조회하는 데이터를 볼 수 있게 허용할지 말지를 결정하는 것이다.

4가지로 격리 수준이 나뉘고 SERIALIZABLE이 아니라면 크게 성능의 개선이나 저하는 발생하지 않는다.

데이터베이스의 격리 수준을 이야기하면 DIRTY READ, NON-REPEATABLE READ, PHANTOM READ가 레벨에 따라 발생할 수도 있고 발생하지 않을 수도 있다.

  • DIRTY READ: 하나의 트랜잭션에서 작업이 완료 되지 않았는데도 다른 트랜잭션에서 볼 수 있게 되는 현상.
  • NON-REPEATABLE READ: 하나의 트랜잭션에서 같은 쿼리 두번 실행 했을 때, 다른 값이 나오는 현상. 한 레코드 값에 초점.
  • PHANTOM READ: 하나의 트랜잭션에서 첫번째 쿼리 결과와 두번째 쿼리 결과가 다른 현상인데 NON-REPEATABLE READ와 다른 점은 이름에서 유추할 수 있듯, 없던 레코드가 생기거나, 있던 레코드가 사라지는 경우이다. 레코드의 존재 유무에 초점.

대부분은 READ COMMITED를 사용하고, MySQL은 REPEATABLE READ를 주로 사용.

READ UNCOMMITTED

각 트랜잭션에서의 변경 내용이 COMMIT이나 ROLLBACK 여부에 상관없이 다른 트랜잭션에서 보임. 더티 리드 발생.

READ COMMITTED

오라클 DBMS에서 기본으로 사용. 온라인 서비스에서 가장 많이 선택한다. 더티 리드는 발생하지 않는다. 하나의 트랜잭션이 실행되는 동안 이전 데이터를 언두로그에 저장한 뒤, 해당 데이터를 다른 트랜잭션에서 조회할 때는 언두로그 데이터를 반환해주고, 트랜잭션이 종료되면 테이블에서 변경된 데이터를 조회하게된다.

DIRTY READ는 발생하지 않지만 NON-REPEATABLE READ는 하나의 트랜잭션(A)이 진행되는 동안 중간에 다른 트랜잭션(B)이 시작되고 종료가 된다면 다른 트랜잭션(B) 전에 조회한 쿼리 결과와 다른 트랜잭션 (B)이 종료된 후의 쿼리 결과가 달라지기 때문에 트랜잭션(A) 내에서는 같은 쿼리가 다른 결과를 내놓게 되는 것이다.

일반적인 웹 프로그램에서는 크게 문제되지 않을 수 있지만, 금전적인 처리와 연결되면 문제가 될 수도 있다.

REPEATABLE READ

MySQLDML InnoDB 스토리지 엔진에서 기본으로 사용되는 격리 수준이다. 이 격리 수주에서는 기본적으로 SELECT 쿼리 문장도 트랜잭션 범위 내에서만 작동한다.

InnoDB 스토리지 엔진은 트랜잭션이 ROLLBACK될 가능성에 대비해 변경되기 전 레코드를 언두 공간에 백업해두고 실제 레코드 값을 변경한다(MVCC). 트랜잭션의 고유한 번호를 가지고, 내 트랜잭션 번호보다 작은 트랜잭션 번호에서 변경한 것만 보여준다.

SERIALIZABLE

가장 단순한 격리 수준이면서 동시에 가장 엄격한 격리 수준이다. 그만큼 동시 처리 성능도 다른 격리 수준보다 떨어진다. 한 트랜잭션에서 읽고 쓰는 레코드를 다른 트랜잭션에서는 절대 접근할 수 없다. InnoDB 스토리지 엔진에서는 갭 락과 넥스트 키 락 덕분에 PHANTOM READ가 발생하지 않는다. (레코드 변경이력 조회는 예외)

6_ 데이터 압축

페이지 압축

MySQL 서버가 디스크에 저장하는 시점에

results matching ""

    No results matching ""