격리수준 (고립수준, Isolation Level)
트랜잭션의 네 가지 주요 성질 중 하나인 고립성에 관한 내용이다.
트랜잭션들의 직렬성이 보장된다면 서로간의 간섭은 없을 것이다. 하지만 병렬로 수행되는 트랜잭션에는 분명 간섭이 존재하고, 이를 격리수준으로 통제하여 얼마만큼의 간섭을 허용할 것인지를 결정하는 것이다.
고립 수준은 병렬적인 트랜잭션을 어느정도 직렬성을 띄게 만들어준다. 그렇기에 당연히 고립 수준이 낮아지면 동시성은 높아지지만 데이터의 정확성은 떨어지게 되고, 고립 수준이 높아지면 데이터 정확성은 높아지지만 동시성은 저하된다.
4가지 격리 수준
격리 수준에는 네 가지가 있다.
1) Read Uncommited
2) Read Commited
3) Repeatable Read
4) Serializable
네 개의 규약은 모두 갱신에 대해서는 독점 로크를 걸고, 트랜잭션이 끝나는 순간까지 보유한다.
차이점은 읽으려는 데이터에 대해 공유로크 (S-Lock) 을 거느냐, 걸지 않느냐, 건다면 언제까지 거느냐 정도이다.
일단 공유로크란 어떤 트랜잭션이 데이터 항목을 읽기 위해 요청하는 로크로, 다른 트랜잭션은 독점된 로크를 읽을 수는 있으나, 기록은 할 수 없다. 즉, S-LOCK은 걸 수 있게 된다.
추가로 X-LOCK (전용 로크)는 다른 트랜잭션은 어떤 LOCK도 걸 수 없게 된다. 즉, 읽을 수도 없다.
본론으로 들어가, 하나씩 설명을 해보자.
Read Uncommited는 공유 로크를 걸지 않는다.
Read Commited는 공유 로크를 걸지만, 읽기가 끝나자마자 로크를 해제한다.
Repeatable Read는 공유 로크를 걸고, 트랜잭션이 끝나는 순간까지 유지한다.
Serializable은 튜플 뿐 아니라 인덱스에 대해서도 공유 로크를 건다.
이러한 점은 어떤 차이가 있을까?
부정 판독 (오손 데이터 읽기) 라는 문제가 있다. 이는 완료되지 않은 트랜잭션이 갱신한 데이터이다.
예를 들어 한 트랜잭션이 update로 데이터를 변경했다. 그 후 다른 트랜잭션이 select로 그 데이터를 읽었는데, 갑자기 원래의 트랜잭션이 rollback을 했다면?
당연히 그 데이터는 오손 데이터가 되고, 잘못된 데이터를 읽게 된 것이다.
이러한 문제는 공유 로크를 걸지 않는 Read Uncommited에서만 일어난다.
T1 | UPDATE | ROLLBACK | ||
T2 | SELECT | COMMIT |
비반독 판독 (반복할 수 없는 읽기) 라는 문제도 있다. 방금 전에 읽은 데이터가, 곧바로 다시 읽었는데 다른 트랜잭션이 변경하여 바뀐 경우이다.
이는 읽기가 끝나자마자 로크를 해제하는 Read Commited와, 애초에 공유로크가 없는 Read Uncommited에서 발생한다.
T1 | UPDATE | ||
T2 | SELECT | SELECT |
마지막 문제는 가상 판독 (팬텀 문제) 이다. Repeatable Read는 튜플에 대해 공유로크만 걸고, 인덱스에 대해서는 걸지 않는다.
그렇기에 현재 읽고 있는 값이 변할 일은 없지만, INSERT로 인한 테이블 자체의 변화에는 대응할 수 없다.
결과적으로 이러한 문제로 인해 데이터를 읽어 테이블을 가져오고, 다시 테이블을 가져왔는데 테이블이 변해있는 상황이다.
T1 | INSERT | ||
T2 | SELECT | SELECT |
종합적으로 격리수준별 발생 가능 문제는 다음과 같다.
'IT 지식 > 데이터베이스' 카테고리의 다른 글
[DB] 두 개 컬럼을 인덱스로 묶고 그 중 하나로만 쿼리를 하면? (0) | 2024.01.16 |
---|---|
ON DELETE(UPDATE) 옵션 (0) | 2024.01.10 |
[PostgreSQL] 컬럼의 Length를 지정해야 하는 이유 (0) | 2023.07.05 |
[DB & BOOT] 트랜잭션 (0) | 2021.05.30 |
[데이터베이스] JSON과 XML (0) | 2021.04.06 |