Post

[DB] 트랜잭션 격리 수준

서론

트랜잭션에 대한 개념과 특징, 상태에 대해 지난 포스팅에서 알아보았다.
트랜잭션의 특징 중 I에 해당하는 isolation(격리성)은 트랜잭션 수행 시에 서로 끼어들면 안된다는 것을 말한다.
데이터베이스는 여러 사용자가 같은 데이터에 접근할 수 있어야 한다. 순차적으로 접근할 수 있다면 쉽게 구현할 수 있겠지만 성능이 나쁠 것이다.

트랜잭션 격리 수준이란?

트랜잭션 격리 수준은 ‘여러 트랜잭션이 동시에 처리될 때 특정 트랜잭션에서 변경하거나 조회하는 데이터를 볼 수 있게 허용할지 말지’를 결정하는 정도이다.
격리 수준은 READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, SERIALIZABLE의 4가지로 나뉘며, 차례대로 뒤로 갈수록 트랜잭션 간의 데이터 격리 정도가 높아지며, 동시 처리 성능이 떨어진다.

각 격리 수준 별로 생기는 문제점

transactional_isolation_problem

  • DIRTY READ
    • 커밋되지 않은 수정 중인 데이터를 다른 트랜잭션에서 읽을 수 있도록 허용할 때 발생하는 현상
    • 어떤 트랜잭션에서 아직 실행이 끝난지 않은 다른 트랜잭션에 의한 변경 사항을 보게 되는 되는 경우
  • NON-REPEATABLE READ
    • 한 트랜잭션에서 같은 쿼리를 두 번 수행할 때, 두 쿼리의 결과가 상이하게 나타나는 비 일관성 현상
    • 한 트랜잭션이 수행중일 때 다른 트랜잭션이 값을 수정 또는 삭제함으로써 나타난다.
  • PHANTOM READ
    • 한 트랜잭션에서 같은 쿼리를 두 번 수행할 때, 첫 번째 쿼리에서 없던 레코드가 두 번째 쿼리에서 나타나는 현상
    • 한 트랜잭션이 수행중일 때 다른 트랜잭션이 새로운 레코드가 삽입함으로써 나타난다.

READ UNCOMMITTED

read_uncommitted

  • 각 트랜잭션의 변경 내용이 COMMIT이나 ROLLBACK 여부에 상관없이 다른 트랜잭션에서 보인다.
  • 사용자 A가 처리 도중 알 수 없는 문제가 발생해 INSERT된 내용(“Lara” 사원)을 ROLLBACK한다고 하더라도 여전히 사용자 B는 “Lara”가 정상적인 사원이라고 생각하고 계속 처리할 문제가 생길 수도 있다.
  • DIRTY READ가 허용되는 격리 수준이며, RDBMS 표준에서는 트랜잭션 격리 수준으로 인정하지 않는다. 이 현상으로 인해 개발자와 사용자가 데이터에 대해 혼동이 생길 수 있다.
  • MySQL에서는 최소한 READ COMMITTED 이상의 격리 수준을 사용할 것을 권장한다.

READ COMMITTED

read_committed

  • Oracle DBMS의 기본 격리 수준이며, 가장 많은 서비스에서 선택되는 격리 수준이다.
  • 특정 트랜잭션에서 데이터를 변경했더라도 COMMIT이 완료된 데이터만 다른 트랜잭션에서 조회할 수 있다.
  • NON-REPEATABLE READ 현상이 생길 수 있다.
    • REPEATABLE READ는 한 트랜잭션 내에서 동일한 SELECT문의 결과가 같아야 한다는 의미이다.
    • 하지만 다른 트랜잭션 내에서 데이터의 변경이나 삭제에 따라 SELECT문의 결과가 달라질 수 있다.

REPEATABLE READ

repeatable_read

  • MySQL의 InnoDB 스토리지 엔진에서 기본으로 사용되는 격리 수준이다.
  • 트랜잭션이 ROLLBACK될 가능성에 대비해 변경되기 전 레코드를 Undo 공간에 백업해두고 실제 레코드 값을 변경한다.(MVCC)
  • 트랜잭션이 시작된 이후에 emp_no가 500000인 “Lara”를 “Toto”로 변경하고 COMMIT했지만, 두 번째 SELECT에서 Undo에 백업된 데이터에 의해 “Lara”의 데이터가 조회된다.
  • 한 트랜잭션 안에서의 SELECT문은 결과가 동일하다는 것을 볼 수 있다.

phantom_read

  • PHANTOM READ 현상이 발생할 수 있다.
    • 다른 트랜잭션에서 수행한 변경 작업에 대해 레코드가 보였다 안 보였다 하는 증상
  • SELECT … FOR UPDATE는 SELECT하는 레코드에 Lock을 걸어야 하는데 Undo 공간에는 잠금을 걸 수 없기 때문에 SELECT… FOR UPDATE나 SELECT … LOCK IN MODE는 현재의 레코드의 값을 가져오기 때문에 바뀐 값을 가져올 수가 있다.
  • MySQL에서는 갭 락과 넥스트 키 락 덕분에 REPEATABLE READ 격리 수준에서도 PHANTOM READ가 발생하지 않는다.

SERIALIZABLE

  • 가장 단순한 격리 수준이면서 동시에 가장 엄격한 격리 수준이다.
  • 동시 성능이 가장 좋지 않다.
  • 읽고 쓰는 레코드에 대해 다른 트랜잭션에서는 절대 접근할 수 없다.
  • PHANTOM READ가 발생하지 않는다.

MySQL에서 격리 수준 보는 방법

MySQL 8.4.2 버전에서 조회했다.
기본 격리 수준은 위에서 언급했듯이 ‘REPEATABLE-READ’이다.

1
SELECT @@GLOBAL(or SESSION).transaction_isolation

스크린샷 2024-11-14 오후 3 18 51

MySQL에서 격리 수준 바꾸는 방법

1
2
3
4
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;

참고

This post is licensed under CC BY 4.0 by the author.