본문 바로가기
DBMS

[DBMS] Transaction의 격리수준 (Isolation Level)

by 도전하는 린치핀 2024. 3. 14.

 

1.  격리수준 (Isolation Level)이란?

  • 트랜잭션(Transaction)간 서로 얼마나 고립되어 있는지 나타내는 수준
  • 한개의 트랜잭션이 다른 트랜잭션이 변경한 데이터에 대한 접근 할 수 있는 강도를 의미한다.
  • Level은 0~3 수준으로 나뉘어져 있으며 레벨이 커질수록 고립의 수준이 높아지고, 성능은 저하될 수 있다.
  • Level 0은 고립이 거의 되어있지 않은 수준이고, Level 3는 완전하게 고립(직렬화)되어 있는 상태이다.

 

2. 격리 수준의 필요성은 무엇일까?

  • 기본적으로 격리 수준은 트랜잭션의 ACID 특성을 보장하기 위해 사용된다.
  • 격리 수준이 낮으면 많은 트랜잭션의 처리가 빨라지지만 데이터의 무결성에 문제가 생길 수 있다.
  • 격리 수준이 높으면 트랜잭션 처리 성능이 저하될 수 있지만 데이터 무결성의 문제를 해결할 수 있다.
  • 따라서 데이터와 데이터를 처리하는 트랜잭션의 특징에 따라 격리 수준을 다르게 설정하여 최적의 성능과 데이터의 무결성 문제를 해결해야 한다.

3. 격리 수준마다 발생할 수 있는 상호작용

(1)의 사진은 각 격리 수준마다 발생할 수 있는 상호작용에 대해서 나타난 것이다.

첫번째 열은 각 격리 수준을 나타내고 첫번째 행은 발생할 수 있는 상호작용이다.

그렇다면 각 상호작용이 어떤 의미인지 알아보자.

 

1. DIRTY READ

  • 커밋되지 않은 수정 중인 데이터를 다른 트랜잭션에서 읽을 수 있도록 허용할 때 발생하는 현상
  • 어떤 트랜잭션에서 아직 실행이 끝난지 않은 다른 트랜잭션에 의한 변경 사항을 보게 되는 되는 경우
  • 만약 1번 트랜잭션이 데이터를 읽고 2번 트랜잭션이 데이터를 수정하고 커밋하지 않은 상태일 때, 1번 트랜잭션이 다시 데이터를 읽는다면 2번 트랜잭션이 커밋하지 않은 상태를 읽는 것으로 만약 2번 트랜잭션이 커밋하지않고 롤백을 진행한다면 1번이 읽은 데이터는 잘못된 값을 읽는 것이다. 



내 계좌에 100,000원이 있고, 은행 업무를 통해 진행할 때 A 트랜잭션(입금)과 B 트랜잭션(잔고 조회 후 사용)이 수행되는 상황을 예로 들어보자.

  1. A 트랜잭션을 수행하기 위해 READ를 진행했을 때 계좌의 값은 100,000원이다.
  2. A 트랜잭션이 50,000원을 내 계좌로 입금하는 업무를 진행하고 커밋을 진행하지 않는다.
  3. 이때, B 트랜잭션이 다시 계좌를 조회한다면 150,000원이라는 결과가 나오기 때문에 150,000원을 사용할 수 있다.
  4. A 트랜잭션이 커밋되지 않고 롤백된다면 계좌에는 100,000원이 있지만, B 트랜잭션에서는 150,000원이라는 결과를 가져와 계좌의 잔고보다 더 많은 돈을 사용할 수 있게 된다.

2. Non-repeatable Read

  • 다른 트랜잭션이 커밋한 데이터만 읽을 수 있게 하는 것 
  • 한 트랜잭션에서 같은 쿼리로 2번이상 조회할 때, 두 쿼리의 결과가 상이하게 나타나는 비 일관성 현상
  • 보통 한 트랜잭션이 수행중일 때 다른 트랜잭션이 값을 수정함으로써 나타난다.

 

내 계좌에 100,000원이 있고, 은행 업무를 통해 진행할 때 A 트랜잭션(입금)과 B 트랜잭션(잔고 조회)이 수행되는 상황을 예로 들어보자.

  1. A 트랜잭션을 수행하기 위해 READ를 진행했을 때 계좌의 값은 100,000원이다.
  2. A 트랜잭션이 50,000원을 내 계좌로 입금하는 업무를 진행하고 커밋을 진행하지 않는다.
  3. 이때, B 트랜잭션이 다시 계좌를 조회한다면 100,000원이라는 결과가 나오기 때문에 DIRTY READ의 문제는 해결되었다.
  4. B 트랜잭션이 READ를 진행한 직후 A 트랜잭션이 커밋된다면 B 트랜잭션은 READ 직후 바로 READ를 한번 더 진행헀는데 150,000원이라는 결과를 가져와 어떤 값이 진짜 계좌의 잔고인지 알 수 없게 된다.

3. Phantom Read

  • 다른 트랜잭션이 커밋(Commit)한 데이터가 있더라도 자신의 트랜잭션에서 읽었던 내용만 사용하는 것을 의미합니다.
  • 한 트랜잭션에서 같은 쿼리를 2번이상 조회했을 때 없던 결과가 조회되는 상황을 말합니다.
  • 보통 한 트랜잭션이 수행중일 때 다른 트랜잭션이 새로운 레코드가 삽입 또는 삭제함으로써 나타난다.

 

내가 100,000원이 들어 있는 계좌 한개를 가질 때, 은행 업무를 통해 진행할 때 A 트랜잭션(새로운 계좌 만들기)과 B 트랜잭션(모든 계좌 조회)이 수행되는 상황을 예로 들어보자.

  1. B 트랜잭션을 수행하기 위해 READ를 진행했을 때 계좌의 수는 100,000원이 들어있는 계좌 한개이다.
  2. A 트랜잭션이 50,000원을 새로운 계좌를 만들어 입금하는 업무를 진행한다.
  3. 이때, B 트랜잭션이 다시 계좌의 수를 조회한다면 100,000원이 들어있는 계좌와 50,000원이 들어있는 계좌 두개가 조회된다.
  4. 이때 사용자는 같은 쿼리를 사용하여 계좌를 조회하였는데 기존에는 없었던 알지 못하는 계좌가 생겨난다.

 

4.  격리 수준

위의 (2)에서 설명한 것 처럼 격리수준은 데이터의 무결성과 트랜잭션 처리 성능과의 trade off 관계를 가지고 있다.

가장 낮은 격리 수준은 빠른 성능을 가지지만 데이터의 무결성의 문제가 많고, 가장 높은 격리 수준은 성능의 저하 문제가 있지만 데이터 무결성의 문제가 해결된다.

 

4-1. Read Uncommitted (Level 0)

  • 어떤 트랜잭션의 내용이 커밋(Commit)이나 롤백(Rollback)과 상관없이 다른 트랜잭션에서 조회가 가능
  • Select문이 실행되는 동안 해당 Data에 Shared Lock이 걸리지 않는다.
  • 따라서, 어떤 사용자가 A라는 데이터를 B라는 데이터로 변경하는 동안 다른 사용자는 아직 완료되지 않은(Uncommitted 혹은 Dirty) 트랜잭션이지만 변경된 데이터인 B를 읽을 수 있다.
  • 이때 DIRTY READ, Non-repeatable Read, Phantom Read가 발생할 수 있다.
  • 데이터베이스의 일관성을 유지할 수 없고 정합성의 문제가 많기 때문에 RDBMS 표준에서는 격리수준으로 인정하지 않는다.

 

4-2. Read Committed (Level 1)

  • 한 트랜잭션의 변경내용이 커밋(Commit)되어야만 다른 트랜잭션에서 조회가 가능한 격리 수준이다.
  • 대부분의 RDBMS에서 기본적으로 사용하는 격리수준입니다.
  • Select문이 실행되는 동안 Shared Lock이 걸리고, 데이터 조회 시 실제 테이블 값이 아니라 Undo 영역에 백업된 레코드 값을 가져옵니다.
  • 트랜잭션이 수행되는 동안 다른 트랜잭션이 접근할 수 없어 대기하게 된다.
  • Commit이 완료된 트랜잭션만 조회할 수 있다.
  • 따라서, 어떤 사용자가 A라는 데이터를 B라는 데이터로 변경하는 동안 다른 사용자는 해당 데이터에 접근할 수 없다.
  • 하지만, 하나의 트랜잭션에서 동일한 쿼리를 사용하여 데이터를 읽었을 때, 같은 결과를 가져오는 것이 아닌 다른 값을 읽어올 수 있다.
  • 이때 동일 쿼리에서 동일한 결과를 가져와야하는 Repeatable Read의 정합성을 어긋나게 된다.
  • 이러한 현상을 Non-Repeatable Read 현상이라고 한다.

 

4-3. Repeatable Read (Level 2)

  • 트랜잭션이 시작되기 전에 커밋된 내용에 대해서만 조회가 가능한 격리 상태
  • 이 격리 수준에서는 Non-Repeatable Read가 발생하지 않는다.
  • 트랜잭션이 완료될 때까지 Select문이 사용하는 모든 데이터에 Shared Lack이 걸린다.
  • 따라서 트랜잭션 범위 내에서 조회한 데이터의 내용은 항상 동일하다.
  • 트랜잭션이 시작 시점 데이터의 일관성을 보장해야 하기 때문에 트랜잭션의 실행시간이 길어질수록 계속 멀티 버전을 관리해야 하는 단점이 발생할 수 있다.
  • 하지만 Level 2의 경우 새로운 데이터가 생겼을 때 조회한 결과가 다른 Phantom Read가 발생할 수 있다.

 

4-4. SERIALIZABLE (Level 3)

  • 가장 단순하면서 엄격한 격리 수준이지만 격리 수준이 높은 만큼 성능 측면에서는 동시 처리성능이 가장 낮다. 
  • SERIALIZABLE에서는 PHANTOM READ가 발생하지 않습니다.
  • 트랜잭션들이 동시에 일어나지 않고, 순차적으로 실행되는 것처럼 동작합니다.
  • 따라서, 다른 사용자는 그 영역에 해당되는 데이터에 대한 수정 및 입력이 불가능하다.
  • 동시 처리 성능이 낮아 거의 사용하지 않는다.

 

 

결국 격리 수준은 데이터의 특징과 DBMS의 특징에 따라서 레벨을 설정하여 효율적인 격리 수준을 설정할 수 있어야 한다.

 

 

 

'DBMS' 카테고리의 다른 글

[DBMS] Index를 통한 SELECT 쿼리 성능 개선  (0) 2024.05.16
[DBMS] RDBMS에서 트랜잭션의 ACID 규칙  (0) 2024.03.13