MySQL 격리 수준
- 트랜잭션 격리 수준이란 여러 트랜잭션이 동시 처리될 때 특정 트랜잭션이 다른 트랜잭션에서 변경하거나 조회하는 데이터를 볼 수 있게 허용할지 말지를 결정하는 것이다.
- READ UNCOMMITED, READ COMMITED, REPEATABLE READ, SERIALIZABLE의 4가지 레벨이 있다.
- 격리 수준이 높을수록 격리 정도가 높아지며 동시 처리 성능은 떨어진다.
- SERIALIZABLE이 아니면 크게 성능 개선이나 저하는 발생하지 않는다.
5.4.1 READ UNCOMMITED
- 각 트랜잭션에서의 변경 내용이 commit이나 rollback 여부에 상관없이 다른 트랜잭션에서 보인다.
- 완료되지 않은 작업이 다른 트랜잭션에서 보이는 현상을 더티 리드(dirty read)라고 한다.
- MySQL을 사용한다면 이 현상을 막기 위해 최소한 READ COMMITED 이상의 격리 수준을 사용할 것을 권장한다.
5.4.2 READ COMMITED
- 오라클 DBMS에서 기본으로 사용되는 격리 수준
- 커밋 완료된 데이터만 다른 트랜잭션에서 조회할 수 있어 더티 리드가 발생하지 않는다.
- READ COMMITED 시나리오
- 특정 레코드를
UPDATE
하면 즉시 테이블에 변경된 값이 기록되고, 변경 전 데이터는 언두 로그에 백업 된다.
- 아직 커밋되지 않았을 때 다른 트랜잭션에서 이 레코드를 조회하게 되면 테이블이 아닌 언두 영역을 읽어 변경 전 데이터를 읽어 온다.
- 변경 값이 커밋이 되어야 다른 트랜잭션에서도 언두 영역이 아닌 변경된 값을 참조할 수 있게 된다.
- READ COMMITED에서는 NON-REPEATABLE READ가 발생한다.
- NON-REPEATABLE READ란 한 트랜잭션에서 처음 조회했을 때와 나주엥 조회했을 때의 데이터 값이 달라지는 경우를 말한다.
- 한 트랜잭션 내에서 같은 조건으로 두 번 조회하는 사이에 다른 트랜잭션에서 해당 조건에 해당하는 레코드를 변경하고 커밋하는 경우에 발생한다.
- 동일 데이터를 여러 번 읽고 변경하는 작업이 금전적인 처리와 연결되면 문제가 될 수도 있다.
5.4.3 REPEATABLE READ
- MySQL의 InnoDB 스토리지 엔진에서 기본으로 사용하는 격리 수준
- NON-REPEATABLE READ 현상이 발생하지 않는다.
- InnoDB는 변경 전 데이터를 언두 영역에 백업하고 실제 레코드를 변경하는 MVCC를 하기 때문이다.
- READ COMMITED에서도 언두 영역을 통해 커밋 전 데이터를 보여준다.
- REPEATABLE READ와의 차이는 언두 영역의 레코드의 여러 버전 중 몇 번째 이전 버전까지 찾아 들어가야 하느냐에 있다.
- 트랜잭션에는 고유한 번호(순차 증가 값)을 가지며 언두 영역에 백업된 레코드에는 변경을 일으킨 트랜잭션 번호가 포함되어 있다.
- 레코드를 조회하는 트랜잭션은 자신의 트랜잭션 번호보다 작은 트랜잭션 번호를 가진 레코드만 언두 영역에서 읽기에 반복 가능한 읽기를 수행할 수 있게 된다.
- REPEATABLE READ에서도 PHANTOM READ라는 부정합이 발생한다.
- A 트랜잭션에서
id>10
조건으로 레코드를 검색했을 때 0건이 나왔다.
- B 트랜잭션에서
id = 11
이라는 레코드를 삽입하고 커밋했다.
- 격리 수준에 REPEATABLE READ이기에 평범하게 다시 조회하면 여전히 0건이 나올 것이다.
SELECT … WHERE id > 10 FOR UPDATE
쿼리로 잠금을 걸어 가져오게 되면 없었던 id = 11
레코드가 조회되게 된다.
- 이 현상은 언두 영역엔 잠금을 걸 수 없기 때문에 발생하는 현상이다.
5.4.4 SERIALIZABLE
- 가장 엄격한 격리 수준으로 그만큼 동시 처리 성능이 떨어진다.
- InnoDB에선 기본적으로 순수한
SELECT
작업엔 아무 잠금도 걸지 않는다.
- 하지만 격리 수준이 SERIALIZABLE일 때는 모든
SELECT
작업에 읽기 잠금을 걸기 때문에 다른 트랜잭션은 잠금이 걸린 레코드를 변경하지 못하게 된다.
- 덕분에 PHANTOM READ는 발생하지 않는다.
InnoDB에선 갭 락과 넥스트 키 락 덕분에 REPEATABLE READ에서도 PHANTOM READ가 발생하지 않기에 SERIALIZABLE을 설정하지 않아도 된다.