본문 바로가기
츄Log/기타 끄적

MySQL 트랜잭션 격리 수준 (isolation level)

by 츄츄🦭 2023. 12. 21.
728x90

 

안녕하세요. 오늘은 MySQL의 격리수준을 알아보겠습니다.

 

트랜잭션에서 격리수준(isolation level)은 

여러 트랜잭션이 동시에 처리될 때, 다른 트랜잭션의 변경사항을 어디까지 허용할 것인지 설정하는 매우 중요한 개념입니다.

 

트랜잭션의 격리수준에 따라서 고립도, 동시 처리 성능, 부정합 정도가 달라지게 됩니다. 

(격리 수준이 높아지면 고립도가 올라가고, 동시 처리 성능이 떨어지며 부정합 정도가 완화된다 라고 직관적으로 이해해볼 수 있습니다.)

 

출처 : Real MySQL 8.0

위 표를 보면 행이 격리수준이고, 밑으로 내려갈 수록 격리 수준이 올라가는 것입니다.

열은 부정합의 종류입니다.

 

먼저 부정합의 종류부터 알아보겠습니다.

 

1. Dirty Read

특정 트랜잭션에서 처리한 작업이 완료되지 않았는 데도 다른 트랜잭션에서 볼 수 있는 현상입니다.

예를들어 A, B 트랜잭션이 동시에 실행되고 있다고 가정해보겠습니다.

1. A가 데이터 X 삽입 

2. B가 데이터 X 조회

3. A가 데이터 X 삽입을 커밋하려는 와중에 알 수 없는 오류로 롤백

=> B는 데이터X가 있다고 인지하고 있어서 업데이트를 하려고 했으나 데이터X는 없어서 오류 발생할 수 있음,

또는 데이터 X를 재조회 했을 때는 없는 데이터라고 나옴

 

Dirty Read는 예시만 보더라도 정합성 문제가 참 많아보입니다. 그래서 Dirty Read를 허용하는 시스템은 거의 없다고 생각합니다. 

(Dirty Read를 허용하고 Dirty Read가 발생해도 괜찮은 서비스는 뭐가 있을까? 고민해봐도 생각 나는 것이 없네요!)

 

2. Non-Repeatable Read

이 부정합은, Repeatable Read가 불가능하다고 이해할 수 있습니다.

그럼 Repetable Read란 무엇일까요?

Repetable Read는 하나의 트랜잭션 내에서 똑같은 SELECT 쿼리를 실행했을 때는 항상 같은 결과를 가져와야 한다는 것입니다.

그렇다면, Non-Repetable Read는 하나의 트랜잭션 내에서 똑같은 SELECT 쿼리를 실행해도 다른 결과가 나올 수 있다는 것입니다.

Non-Repetable Read의 예시를 들어보겠습니다.

1. A가 트랜잭션 T 시작

2. A가 트랜잭션 T 안에서 데이터 X를 조회

3. B가 데이터 X를 업데이트 후 커밋 

4. A가 트랜잭션T 안에서 데이터 X를 조회하였으나 B에 의해 업데이트 되어서 처음 조회한 것과 결과가 다름

 

3. Phantom Read

일반적으로 범위 조건(Range Condition)을 사용하는 쿼리에서 발생합니다.

범위 조건은 특정 범위 내의 데이터를 조회하는데 사용되는데, 특히 트랜잭션이 실행 중일 때 다른 트랜잭션에서 새로운 데이터를 추가하거나 삭제하는 경우 Phantom Read가 발생할 수 있습니다.

 

부정합 종류를 알아보았으니, 격리 수준을 알아보겠습니다.

 

1. READ UNCOMMITED

각 트랜잭션의 변경 내용이 COMMIT이나 ROLLBACK 여부와 상관 없이 다른 트랜잭션에서 보이는 수준입니다.

이 수준에서는 위에 설명한 Dirty Read가 허용됩니다.

 

2. READ COMMITED

일반적으로 가장 많이 사용되는 수준이며, 이름 그대로 커밋 완료된 데이터만 다른 트랜잭션에서 조회할 수 있으므로 Dirty Read가 발생하지 않습니다. MySQL은 이 수준부터 언두로그를 활용한 MVCC 기술을 활용하여 격리수준을 보장합니다. 

 

3. REPETABLE READ

READ COMMITED더라도 위에 설명한 Non-Repetable Read가 발생할 수 있습니다. 이를 보장할 수 있는 수준이 REPETABLE READ 입니다. 

InnoDB엔진에서 모든 트랜잭션은 고유한 트랜잭션 번호가 있는데, 언두영역에 백업된 모든 레코드는 이 트랜잭션 번호를 포함하고 있습니다. 그러므로 현재 자신의 트랜잭션 번호보다 작은 트랜잭션에서 변경한 것들만 보이게 됩니다. 

 

4. SERIALIZABLE

가장 엄격한 격리 수준이며 잘 이용하지 않습니다. MySQL은, 잠금 없는 읽기가 가능한데 이 격리 수준에서는 shared lock을 걸어 읽기 작업을 수행합니다. shared lock을 걸었으므로 shared lock이 모두 풀리기 전까지 쓰기 작업을 못하므로 동시 처리 성능이 매우 떨어지지만 위에서 이야기한 Phantom Read는 발생하지 않습니다. 하지만 MySQL은 특수한 락(갭락, 넥스트 키락)을 통해 REPETABLE READ에서도 Phantom Read가 발생하지 않기 때문에 굳이 이 격리 수준을 사용할 필요는 없습니다. 

 


도움 : Real MySQL 8.0

728x90