Real MySQL
5.4 MySQL의 격리 수준
kidmillionaire1998
2024. 8. 15. 21:47
- 트랜잭션 격리 수준이란?
- 여러 트랜잭션이 동시에 처리될 때 특정 트랜잭션이 다른 트랜잭션에서 변경하거나 조회하는 데이터를 볼 수 있게 허용할지 말지를 결정하는 것
- READ UNCOMITTED(Dirty Read 발생)은 일반적인 데이터베이스에서 사용하지 않는다.
- SERIALIZABLE은 동시성이 중요한 데이터베이스에서 거의 사용되지 않는다.
- SERIALIZABLE 격리 수준이 아니라면 크게 성능의 개선이나 저하는 발생하지 않는다.
- REPEATABLE READ 격리수준에서 PHANTOM READ는 Inno DB 한정해서 발생하지 않는다.
READ UNCOMMITED
- 각 트랜잭션에서의 변경 내용이 COMMIT이나 ROLLBACK 여부에 상관없이 다른 트랜잭션에서 보인다.
- 해당 예시에서 사용자 A가 Insert된 내용을 Rollback한다고 하더라도 여전히 사용자 B는 "Lara"가 정상적인 사원이라고 생각하고 처리한다.
- Dirty Read란?
- 어떤 트랜잭션에서 처리한 작업이 완료되지 않았는데도 다른 트랜잭션에서 볼 수 있는 현상
- 데이터가 나타났다가 사라졌다 하는 현상을 초래하므로 혼란을 초래
- MySQL을 사용한다면 최소 READ COMMITTED 이상의 격리수준을 사용할 것을 권장
- 어떤 트랜잭션에서 처리한 작업이 완료되지 않았는데도 다른 트랜잭션에서 볼 수 있는 현상
READ COMMITTED
- 어떤 트랜잭션에서 데이터를 변경했더라도 COMMIT이 완료된 데이터만 다른 트랜잭션에서 조회 가능하다.
- Dirty Read가 발생하지 않는다.
- 사용자 A가 emp_no = 500000인 사원의 first_name을 "Lara"에서 "Toto"로 변경
- 새로운 값인 "Toto"는 employees 테이블에 즉시 기록된다.
- 이전 값인 "Lara"는 언두 영역으로 백업된다.
- 사용자 A가 커밋을 수행하기 전에 사용자 B가 emp_no = 500000인 사원을 SELECT하면 테이블이 아니라 언두 영역에 백업된 레코드에서 값을 가져오기 때문에 "Toto"가 아니라 "Lara"가 조회된다.
- NON-REPEATABLE READ란?
- 하나의 트랜잭션 내에서 똑같은 SELECT 쿼리를 실행했을 때는 항상 같은 결과를 가져와야 한다는 "REPEATABLE READ" 정합성에 어긋나는 것
- 사용자 B의 경우 같은 트랜잭션에서 같은 쿼리에 대한 결과가 다르다 (결과 없음 -> 결과 1건 반환)
- 문제 상황 예시
- 하나의 트랜잭션에서 동일 데이터를 여러 번 읽고 변경하는 작업이 금전적인 처리와 연결되었을 때
- 다른 트랜잭션에서 입금/출금 처리가 진행될 때 오늘 입금된 금액의 총합을 조회
- REPEATABLE READ가 보장되지 않기 때문에 총합을 계산하는 SELECT 쿼리는 실행될 때마다 다른 결과를 가져온다.
- 하나의 트랜잭션에서 동일 데이터를 여러 번 읽고 변경하는 작업이 금전적인 처리와 연결되었을 때
- SELECT 트랜잭션 내부 vs 외부
- READ COMMITTED
- 차이가 별로 없다
- REPEATABLE READ
- 기본적으로 SELECT 쿼리 문장도 트랜잭션 범위 내에서만 동작한다.
- START TRANSACTION(BEGIN) 명령으로 트랜잭션을 시작한 상태에서 온종일 동일한 쿼리를 반복해서 실행해봐도 동일한 결과만 보게 된다.
- READ COMMITTED
REPEATABLE READ
- InnoDB 스토리지 엔진에서 기본으로 사용되는 격리 수준
- 바이너리 로그를 가진 MySQL서버에서는 최소 REPEATABLE READ 격리 수준을 사용해야 한다.
- MVCC
- 트랜잭션이 ROLLBACK될 가능성에 대비해 변경되기 전 레코드를 Undo 공간에 백업해두고 실제 레코드 값을 변경한다.
- 언두 영역에 백업된 이전 데이터를 이용해 동일 트랜잭션 내에서는 동일한 결과를 보여줄 수 있게 보장한다.
- cf) READ COMMITTED도 MVCC를 이용해 COMMITT되기 전의 데이터를 보여준다.
- REPEATABLE READ와 READ COMMITTED의 차이는 Undo 영역에 백업된 레코드의 여러 버전 가운데 몇 번째 이전 버전까지 찾아 들어가야 하느냐에 있다.
- MVCC를 보장하기 위해 실행 중인 트랜잭션 가운데 가장 오래된 트랜잭션 번호보다 앞선 Undo 영역의 데이터는 삭제할 수 없다.
- TX 번호
- 사용자 A : 12 , 사용자 B : 10
- 사용자 B의 10번 트랜잭션 안에서 실행되는 모든 SELECT 쿼리는 트랜잭션 번호가 10보다 작은 트랜잭션 번호에서 변경한 것만 보이게 된다.
- 트랜잭션이 장시간 지속된다면 undo이 백업된 데이터로 무한정 커질 수 있어 서버 처리 성능이 떨어질 수 있다.
- PHANTOM READ란?
- 다른 트랜잭션에서 수행한 변경 작업에 의해 레코드가 보였다가 안 보였다 하는 현상
- 일반적으로 REPEATABLE READ에서는 Phantom Read가 발생하지 않는다.
출처 : https://mangkyu.tistory.com/299 - 잠금 있는 읽기(SELECT FOR UPDATE)를 실행할 경우 데이터 조회가 언두 로그가 아닌 테이블에서 일어난다.
- 이와 같이 MVCC로 해결할 수 없지만, Inno DB의 경우 갭락을 이용하여 이를 해결한다.
- 다른 트랜잭션 (12번)에서의 INSERT문은 갭락으로 인해 트랜잭션(10번)이 끝날 때 까지 대기 상태에 있다.
- SERIALIZABLE에서도 언급되겠지만, Inno DB의 경우 순수한 SELECT의 경우 잠금 없이 수행되기 때문에 일반적인 SELECT의 경우에는 MVCC로 해결된다.
- Phantom Read가 발생할 수 있는 예외적인 경우
- 같은 트랜잭션 내 SELECT => SELECT FOR UPDATE
출처 : https://mangkyu.tistory.com/299 - 트랜잭션(10번)에서 처음 SELECT의 경우 읽기 잠금 없이 읽기 때문에 갭락이 걸리지 않는다.
- 갭락이 걸리지 않기 때문에 다른 트랜잭션(12번)에서 새로운 값이 INSERT 가능하다.
- 트랜잭션(12번)에서 SELECT FOR UPDATE로 데이터를 조회하는데, 위에서 언급한 대로 읽기 있는 잠금은 테이블을 조회하기 때문에, MVCC를 통해 해결이 불가능하며, 갭락이 없었기 때문에 이미 새로운 데이터는 추가되어있다.
- 같은 트랜잭션 내 SELECT => SELECT FOR UPDATE
- 케이스 정리
- SELECT FOR UPDATE => SELECT : 갭락으로 해결
- SELECT FOR UPDATE => SELECT FOR UPDATE : 갭락으로 해결
- SELECT => SELECT : MVCC를 통해 해결, 언두 로그 조회
- SELECT => SELECT FOR UPDATE : 팬덤 리드 해결 불가능
SERIALIZABLE
- 읽기 작업도 공유 잠금(읽기 잠금)을 획득해야만 하며, 동시에 다른 트랜잭션은 그러한 레코드를 변경하지 못하게 된다.
- 한 트랜잭션에서 읽고 쓰는 레코드를 다른 트랜잭션에서는 절대 접근할 수 없다.
- 가장 단순 / 엄격한 격리 수준
- 동시 처리 성능이 떨어진다.
- PHANTOM READ가 발생하지 않는다.
- Inno DB 스토리지 엔진에서는 갭 락과 넥스트 키 락 덕분에 REPEATABLE READ에서도 PHANTOM READ가 발생하지 않기 때문에 사용할 필요성이 떨어진다.
- Inno DB의 경우 기본적으로 순수한 SELECT의 작업은 아무 레코드 잠금도 설정하지 않고 실행된다.
참고
https://product.kyobobook.co.kr/detail/S000001766482
Real MySQL 8.0 (1권) | 백은빈 - 교보문고
Real MySQL 8.0 (1권) | MySQL 서버를 활용하는 프로젝트에 꼭 필요한 경험과 지식을 담았습니다!《Real MySQL 8.0》은 《Real MySQL》을 정제해서 꼭 필요한 내용으로 압축하고, MySQL 8.0의 GTID와 InnoDB 클러스
product.kyobobook.co.kr
https://mangkyu.tistory.com/299
[MySQL] 트랜잭션의 격리 수준(Isolation Level)에 대해 쉽고 완벽하게 이해하기
이번에는 트랜잭션 격리 수준(Isolation Level)에 대해 알아보도록 하겠습니다. 아래의 내용은 RealMySQL과 MySQL 공식 문서 등을 참고하여 작성하였으며, 모든 내용은 InnoDB를 기준으로 설명합니다. 해
mangkyu.tistory.com