데이터베이스 4: 트랜잭션 격리 수준 (Isolation Levels) 정의, 뜻, 개념, 예시

트랜잭션 격리 수준

데이터베이스 트랜잭션의 ACID 특성이 완벽하게 지켜질 경우, 동시성이 떨어지기 때문에 데이터베이스의 성능이 떨어집니다. 따라서 데이터베이스에서는 트랜잭션 격리 수준 (Isolation Levels) 이라는 개념을 도입하여, 동시성을 높일 수 있는 방법을 제공합니다.

이번 글에서는 데이터베이스의 동시성을 관리하는 “트랜잭션 격리 수준 (Isolation Level)” 에 대하여 상세하게 설명드리겠습니다.


트랜잭션 격리 수준 (Isolation Levels) 이란, 여러 트랜잭션이 동시에 처리될 때, 트랜잭션이 얼마나 서로 격리 (고립) 되어 있는지 정도를 의미합니다.

즉, 트랜잭션 격리 수준 (Isolation Levels) 을 통해서 특정 트랜잭션이 서로 다른 트랜잭션이 편집 / 수정한 데이터를 볼 수 있도록 허용 여부를 결정할 수 있습니다.

 

격리 수준 등장 배경

데이터베이스 트랜잭션의 ACID 원칙이 완벽히 지켜질 경우, 트랜잭션은 순차적으로 하나씩 작업을 실행해야 합니다. 이는 데이터베이스의 성능 저하로 이어지기 때문에, 트랜잭션 ACID 특성은 모두 지켜지기 어렵습니다.

그렇기 때문에 데이터베이스 엔진은 ACID 원칙을 희생하여 동시성을 얻을 수 있는 방법을 제공합니다. 이것이 바로 트랜잭션 격리 수준 (Transaction Isolation Level) 입니다.

(트랜잭션의 Isolation 원칙을 덜 지키는 격리 수준을 사용할수록, 다양한 문제가 발생할 가능성은 커지지만, 트랜잭션의 높은 동시성 덕분에 데이터베이스의 성능은 높아집니다.)

격리 수준 (Isolation Levels) 의 종류

트랜잭션 격리 수준은 다음과 같이 4가지 종류가 있습니다.

  • 0. Read Uncommitted (Level 0)
  • 1. Read Committed (Level 1)
  • 2. Repeatable Read (Level 2)
  • 3. Serializable (Level 3)

각각의 격리 수준에 대하여 상세하게 설명드리겠습니다.

 

0. Read Uncommitted (Level 0)

Read Uncommitted (Level 0)각 트랜잭션에서 수정 / 변경한 데이터를 COMMIT / ROLLBACK 여부에 상관 없이 다른 트랜잭션에서 값을 읽을 수 있는 격리 수준입니다. 트랜잭션에서 처리중인 데이터를 다른 트랜잭션이 읽는 것을 허용하는 가장 낮은 수준의 격리 수준입니다.

 

사용 예시

사실 Read Uncommitted (Level 0) 은 안전성이 떨어지기 때문에 큰 서비스를 구성하는 데이터베이스에서는 사용하기 어렵습니다.

노션의 데이터베이스가 Read Uncommitted (Level 0) 를 사용하고 있는 대표적인 예시입니다. 데이터베이스에 접근할 수 있는 모두가 동시에 수정 / 편집이 가능하다는 특징이 있습니다.

 

구현 방법

Read Uncommitted (Level 0) 는 트랜잭션이 SELECT 문장을 수행한다고 하더라도 해당 데이터에 데이터베이스 락 (Database Lock) 을 전혀 걸지 않음으로써 구현할 수 있습니다.

 

문제점

Read Uncommitted (Level 0) 는 데이터베이스의 일관성 (Consistency) 을 유지할 수 없다는 문제점이 있습니다. 따라서 Dirty Read 가 발생할 수 있습니다.

  • Dirty read: 아직 커밋되지 않은 (확실하지 않은) 중간 처리 데이터를 읽을 수 있는 문제
Read Uncomitted
Read Uncommitted는 dirty read 현상이 생길 수 있습니다. (이미지 출처: https://nesoy.github.io/articles/2019-05/Database-Transaction-isolation)

 

1. Read Committed (Level 1)

Read Committed (Level 1)COMMIT 된 데이터만 읽도록 제한하는 격리 수준 입니다. 특정 트랜잭션이 작업을 수행하는 동안 다른 트랜잭션은 해당 데이터에 접근할 수 없도록 합니다.

 

사용 예시

Read Committed (Level 1) 는 범용적으로 사용되는 데이터베이스 격리 수준으로, Oracle DB, SQL Server 등에서 사용됩니다.

 

구현 방법

Read Committed (Level 1) 는 트랜잭션이 데이터를 조회하는 SELECT 문장이 수행되는 동안 해당 데이터에 공유 락 (Shared Lock) 을 걸어둠으로써 구현할 수 있습니다.

 

문제점

Read Committed (Level 1) 는 Dirty Read와 같은 현상은 발생하지 않지만 Non-repeatable Read 가 발생할 수 있습니다.

  • Non-repeatable Read: 한 트랜잭션 안에서 같은 Read 쿼리를 두 번 실행했을 때, 다른 값이 나오는 Read 현상
Non Repeatable Read
Read Committed는 non-repeatable read 현상이 생길 수 있습니다. (이미지 출처: https://nesoy.github.io/articles/2019-05/Database-Transaction-isolation)

 

2. Repeatable Read (Level 2)

Repeatable Read (Level 2)특정 트랜잭션이 수행되는 시점에 이미 COMMIT 완료된 데이터만 읽도록 제한하는 격리 수준 입니다. 

트랜잭션 범위 내에서 조회한 데이터는 항상 동일함을 보장할 수 있다는 특징이 있습니다. 따라서, 다른 사용자는 트랜잭션 영역에 해당되는 데이터에 대한 수정 / 편집할 수 없습니다. (하지만 데이터 삽입은 가능합니다.)

 

사용 예시

Repeatable Read (Level 2) 는 Read Committed 과 함께 범용적으로 사용되는 데이터베이스 격리 수준으로, MySQL DBMS, Maria DB, InnoDB 등에서 사용됩니다.

 

구현 방법

Repeatable Read (Level 2) 는 트랜잭션이 처음으로 READ (SELECT) 를 수행한 시간을 기록합니다. 그리고 그 이후에는 모든 READ 작업을 수행할 때, 미리 기록해둔 시점의 스냅샷(snapshot) 을 기준으로 READ 를 수행합니다.

그러므로 다른 트랜잭션이 COMMIT 된다고 하더라도 업데이트된 데이터는 보지 않습니다. 첫 READ 를 수행하는 시점의 스냅샷을 기준으로 보기 때문입니다.

 

문제점

Repeatable Read (Level 2) 는 Non-repeatable Read 나 Dirty Read 가 일어나지 않지만, Phantom Read 가 발생할 수 있습니다.

  • Phantom Read: 첫 번째 쿼리 수행 결과와 두 번째 쿼리 수행 결과가 다른 것
Phantom Read
Repeatable Read는 phantom read 현상이 생길 수 있습니다 (이미지 출처: https://nesoy.github.io/articles/2019-05/Database-Transaction-isolation)

 

3. Serializable (Level 3)

Serializable (Level 3) 은 가장 엄격한 트랜잭션 격리 수준으로, 한 트랜잭션이 READ (SELECT) 하는 모든 데이터에 배타 락 (Exclusive Lock) 이 걸리게 됩니다. 따라서, 트랜잭션은 다른 트랜잭션이 접근한 데이터를 조회하거나 수정이 불가능합니다.

완벽한 직렬화를 바탕으로 작동하기 때문에 완벽한 읽기 일관성 모드를 제공한다는 특징이 있습니다.

 

사용 예시

Serializable (Level 3) 은 성능 이슈가 발생할 수 있기 때문에, 하지만 데이터 웨어하우스 (Data warehouse) 같은 특수한 목적에서만 사용되며, 일반적인 데이터베이스에서는 사용하지 않습니다.

 

구현 방법

Serializable (Level 3) 은 트랜잭션이 완료될 때까지 READ (SELECT) 작업을 수행하는 모든 데이터에 배타 락 (Exclusive Lock) 을 걸어둡니다. 배타 락에 의하여 모든 데이터베이스 트랜잭션은 락이 풀릴 때까지 기다리게 됩니다.

 

문제점

Serializable (Level 3) 은 배타 락 (Exclusive Lock) 을 사용하기 때문에 성능이 떨어질 수 있습니다. 또한, 무분별한 배타 락으로 인하여 데드락이 생기기 쉽습니다.

 

마치며

트랜잭션 격리 수준 (Isolation Level) 에 대한 이해를 바탕으로 데이터베이스의 작동을 공부하면, 더 적절한 데이터베이스를 선택할 수 있습니다. 트랜잭션 격리 수준은 개발자 기술 면접에서 데이터베이스 관련된 심화 질문 주제입니다. 

 

함께 읽으면 좋은 글

 

Reference

Leave a Comment