트랜잭션의 격리 수준 및 필요성
트랜잭션의 격리성(Isolation)은 트랜잭션 수행시 서로 끼어들지 못하는 것을 말한다.
복수의 병렬 트랜잭션은 서로 격리되어 마치 순차적으로 실행되는 것처럼 작동되어야 하고, 데이터베이스는 여러 사용자가 같은 데이터에 접근할 수 있어야 한다.
만약 Locking을 통해 동시에 수행되는 수많은 트랜잭션들을 순서대로 처리하는 방식으로 구현한다면 데이터베이스의 성능은 떨어지게 될 것이다.
하지만 그렇다고해서 성능을 높이기 위해 Locking의 범위를 줄인다면 잘못된 값이 처리될 문제가 발생하게 된다.
트랜잭션 수준 읽기 일관성을 지키기 위해 필요하다.
다시 말하자면, 동시성 제어 문제 해결을 위해서이다.
따라서 트랜잭션을 여러개의 격리 수준으로 나누어 격리성을 보장한다.
※ 트랜잭션 수준 읽기 일관성
트랜잭션이 시작된 시점으로부터 일관성 있게 데이터를 읽어 들이는 것을 말한다.
하나의 트랜잭션이 진행되는 동안 다른 트랜잭션에의해 변경사항이 발생하더라도 이를 무시하고 계속 일관성 있는 데이터를 보여준다. (물론 트랜잭션 자신이 발생한 변경사항은 읽을 수 있다)
※ 동시성 제어 : 동시에 실행되는 트랜잭션이 작업을 성공적으로 마칠 수 있도록 트랜잭션의 실행 순서를 제어하는 기법
트랜잭션 격리성의 종류
트랜잭션의 격리 수준은 다음과 같다.
- SERIALIZABLE (트랜잭션 레벨 3)
- REPEATABLE_READ (레벨 2)
- READ_COMMITED (레벨 1)
- READ_UNCOMMITED (레벨 0)
아래로 갈수록 동시성이 강해지지만 격리성은 약해지고, 역방향은 반대가 된다.
예를 들어 SERIALIZABLE은 격리성은 강한데 반해 동시성은 약하다.
또한 각 단계마다 나타나는 현상이 있다.
REPEATABLE_READ은 팬텀 리드, READ_COMMITED는 팬텀 리드, 반복 가지 않은 조회가 발생하며 READ_UNCOMMITED는 팬텀 리드, 반복 가능하지 않은 조회, 더티 리드가 발생할 수 있다.
각 단계마다 나타나는 현상에 대해서는 아래에서 한번에 설명하겠다.
격리 수준
READ_UNCOMMITED (트랜잭션 레벨 0)
- 가장 낮은 격리 수준이다.
- 트랜잭션에서 처리 중인 아직 커밋되지 않은 데이터를 다른 트랜잭션이 읽는 것을 허용한다.
- 가장 빠르다.
- 데이터 무결성을 위해 되도록이면 사용하지 않는 것이 이상적이나, 몇몇 행이 제대로 조회되지 않더라도 괜찮은 거대한 양의 데이터를 '어림잡아' 집계하는 데에 사용하는 것은 괜찮다.
READ_COMMITED (트랜잭션 레벨 1)
- 가장 많이 사용되는 격리 수준으로 많은 RDBMS에서 기본값으로 설정되어 있다.
- READ_UNCOMMITED과는 달리 다른 트랜잭션이 커밋하지 않은 정보는 읽을 수 없다. 즉, 커밋이 완료된 데이터에 대해서만 조회를 허용한다.
- 실제 테이블 값을 가져오는 것이 아니라 Undo 영역에 백업된 레코드에서 값을 가져온다.
- 어떤 트랜잭션이 접근한 행을 다른 트랜잭션이 수정할 수 있다.
- 예를 들어 트랜잭션 A가 수정한 행을 트랜잭션 B가 수정할 수도 있다. 이 때문에 트랜잭션 A가 같은 행을 다시 읽을 때 다른 내용이 발견될 수 있다.
REPEATABLE_READ (레벨 2)
- 하나의 트랜잭션이 수정한 행을 다른 트랜잭션이 수정할 수 없도록 막아주지만 새로운 행을 추가하는 것은 막지 않는다. 따라서 이후에 추가된 행이 발견될 수도 있다.
SERIALIZABLE (트랜잭션 레벨 3)
- 말 그대로 트랜잭션을 순차적으로 진행시키는 것을 말한다.
- 여러 트랜잭션이 동시에 같은 행에 접근할 수 없다.
- 선행 트랜잭션이 특정 테이블을 읽는 경우(SELECT) 공유 잠금(Shared Lock)을 걸어 다른 트랜잭션에서 해당 테이블의 데이터를 UPDATE, DELETE, INSERT 하지 못하도록 막는다.
- 매우 엄격한 수준으로 해당 행에 대해 격리시키고 이후 트랜잭션이 해당 행에 대해 일어난다면 기다려야 한다.
- 교착 상태가 일어날 확률도 많고 가장 성능이 떨어지는 격리 수준이다.
격리 수준에 따라 발생하는 현상
격리 수준에 따라 발생하는 현상으로 3가지 현상이 존재한다.
- Phantom Read (팬텀 리드)
- Non-Repeatable Read (Inconsistent Analysis, 반복 가능하지 않은 조회)
- Dirty Read (Uncommitted Dependency, 더티 리드)
Phantom Read (팬텀 리드)
팬텀 리드는 한 트랜잭션 내에서 동일한 쿼리를 두번 이상 보냈을 때 첫번째 쿼리에서 없던 레코드가 두번째 쿼리에서 나타나는 현상을 말한다.
트랜잭션 도중 새로운 레코드 삽입을 허용하기 때문에 나타나는 현상으로 이를 방지하기 위해 쓰기 잠금(write lock)을 걸어야 한다.
예를 들어 사용자 A가 회원 테이블에서 age가 12 이상인 회원들을 조회하는 쿼리를 보낸다고 해보자
만약 해당 결과로 3개의 테이블이 조회된다고 하자. 그다음 사용자 B가 age가 15인 회원 레코드를 삽입한다.
그러면 그다음에는 3개가 아닌 4개의 테이블이 조회된다.
Non-Repeatable Read (Inconsistent Analysis, 반복 가능하지 않은 조회)
한 트랜잭션 내의 같은 행에 두번 이상 조회가 발생했는데 그 사이에 다른 트랜잭션이 값을 수정 또는 삭제함으로써 그 값이 다른 경우를 가리킨다.
금전적 처리와 연결된 서비스에서 문제가 발생할 수 있다.
트랜잭션B에서 1번 상품의 총 투자액을 조회 👉 100만원이 조회됨
트랜잭션A에서 1번 상품의 총 투자액을 120만원으로 바꾸고 COMMIT
트랜잭션B에서 1번 상품의 총 투자액을 다시 조회 👉 120만원이 조회됨 (NON-REPEATABLE READ 발생)
팬텀 리드와의 다른 점은 반복 가능하지 않은 조회는 행 값이 달라질 수도 있지만 팬텀 리드는 다른 행이 선택될 수도 있다는 것을 의미한다.
Dirty Read (Uncommitted Dependency, 더티 리드)
더티 리드는 반복 가능하지 않은 조회와 유사하며 한 트랜잭션이 실행 중일 때 다른 트랜잭션에 의해 수정되었지만 아직 '커밋되지 않은' 행의 데이터를 읽을 수 있을 때 발생한다.
예를 들어 사용자 A가 1번 상품의 총 투자액을 100에서 120으로 변경한 내용이 '커밋되지 않은' 상태라도 그 이후 사용자가 B가 조회한 결과가 120으로 나오는 경우를 말한다.
참고
'CS > 데이터베이스' 카테고리의 다른 글
[데이터베이스] 병행 제어 (Concurrency Control) (0) | 2022.07.27 |
---|---|
[데이터베이스] 무결성 (Integrity) (0) | 2022.07.26 |
[데이터베이스] 트랜잭션 (Transaction) (0) | 2022.07.22 |
[데이터베이스] 정규화 (Normalization) (0) | 2022.07.22 |
[데이터베이스] Index (인덱스) (0) | 2022.07.22 |
영차영차 성장 블로그
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!