Reference :  CS 공부 비서, midas님의 velog


Q&A

Q.  트랜잭션의 각 격리 수준에 대해서 설명하고, 각 수준에서 일어날 수 있는 문제에 대해 설명해주세요

A. 나의 답변

* 트랜잭션은 데이터베이스의 논리적 수행 단위라고 할 수 있는데, 가지고 있는 여러가지 특징 중 격리성에 대한 특징이 있다.
격리성이란 트랜잭션들이 동시에 실행될 때 서로 영향을 미치지 않도록 격리하는 성질을 의미한다.

* 격리 수준은 4가지로 나눌 수 있는데, 하위 단계로 갈수록 격리 수준이 높아지지만 동시처리의 성능은 떨어진다.
1) Read Uncommitted
2) Read Committed
3) Repeatable Read
4) Serializable 


Best Answers

★김*님의 답변
격리성 관련 문제점을 해결하기 위해서 ANSI 표준에서 트랜잭션의 격리성과 동시 처리 성능 사이에 Trade-off 를 두고 4단계 격리수준을 나눴다.

0 - 한 트랜잭션의 변경된 내용을 commit이나 rollback과 상관 없이 다른 트랜잭션에서 읽을 수 있다
문제점 : 더티 리드(Dirty Read) 발생 가능성 존재한다, 데이터 정합성에 문제가 많다

1 - commit이 완료된 데이터만 조회 가능하다
문제점 : Non-repeatable Read 발생 가능성 존재한다, 잠금이 발생하므로 속도나 성능에 있어서 느릴 수 있다, 트랜잭션 간 고립성을 완전히 보장하지 못한다

2 - 트랜잭션이 시작되기 전에 커밋된 내용에 관해서만 조회할 수 있다
문제점 : 다른 사용자는 트랜잭션 영역에 해당되는 데이터에 대한 수정이 불가능하다, 잠금이 적용되는 범위가 넓어져 성능과 속도가 느려진다

3 - 한 트랜잭션을 다른 트랜잭션으로부터 완전히 분리한다
문제점 : 동시처리 능력이 다른 격리수준보다 떨어지며, 성능저하 발생한다


★김*님의 답변
트랜잭션 격리 수준이란 여러 트랜잭션 동시 처리시, 서로 얼마나 고립되었는지를 나타낸 것으로, 한 트랜잭션이 다른 트랜잭션에 변경한 데이터를 볼 수 있도록 허용할 것인지 결정하는 것이다. ACID와 같은 특성으로 트랜잭션이 독립적인 수행을 하도록 Locking을 통해 다른 트랜잭션 관여 여부를 막는데, 효율적인 Locking을 위해 격리수준을 나눈다.

격리 수준 (Isolatio) 종류
레벨 0. Read Uncommitted
- Select 문장 수행 중 해당 데이터에 Shared Lock이 걸리지 않음
- 일관성 유지 불가
- 문제점 : Dirty Read
- user1이 data A 를 B로 변경하는 도중 user2가 data를 B로 읽게되는 현상 (커밋 X)

레벨 1. Read Committed
- Select 문장 수행 중 해당 데이터에 Shared Lock이 걸림
- 트랜잭션 수행 중 다른 트랜잭션이 접근할 수 없어 대기
- 커밋된 트랜잭션만 조회 가능
- Non-Repeatable Read 발생
- A 트랜잭션에서 1번 데이터 조회 : 1
- B 트랜잭션에서 1번 데이터를 2로 바꾸고 커밋
- A 트랜잭션에서 1번 데이터 조회 : 2

레벨 2. Repeatable Read
- 트랜잭션 완료 전까지 SELECT 내의 모든 데이터에 Shared Lock
- 트랜잭션이 범위 내에 조회한 데이터 내용이 항상 동일함을 보장

레벨 3. Serializable
- 트랜잭션 완료 전까지 SELECT 내의 모든 데이터에 Shared Lock
- 완벽한 읽기 일관성 모드 제공



★권*님의 답변
트랜잭션의 각 격리 수준에 대해 얘기하기 이전에 몇 가지 개념을 정리하려 한다. 트랜잭션이란 데이터의 수정/읽기하는 명령을 의미한다.
커밋은 데이터의 영구적인 저장을 의미한다. 
DB의 각 격리수준이 나오는 이유는 DB가 값을 수정하고, 다른 트렌젝션이 값을 읽고 롤백할 경우 데이터의 일관성을 잃는 문제가 있다. 이런 문제들을 갖고 어떤 방법론을 쓸 건지 나눈 것이다.
예를들면 데이터를 수정할 때 데이터를 수정 전의 값 기준으로 한다. 데이터를 수정 후의 기준으로 한다. 데이터를 커밋하기 이전의 기준으로 한다. 이후로 한다. 와 같이 나눠진다.

자세히 살펴보면 다음과 같은 방법이 있다.

READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ
SERIALIZABLE

READ UNCOMMITTED
커밋하지 않아도 수정한 결과를 계산 값으로 쓴다. 이때 위에 말한 것처럼 롤백을 사용할 경우 데이터의 일관성을 잃는다.


READ COMMITTED
커밋한 결과만으로 값을 쓴다. 그렇다면 데이터의 일관성이 유지되지만 또 다른 문제점이 존재한다. DB가 멀티스레드로 트렌젝션을 동시에 처리할 때이다. 이럴 경우 동기화가 되지않아서 어떤 것은 수정되기 이전 값을 쓰고 이후에 커밋되어 수정된 값을 쓰고 같은 문제가 발생한다.


REPEATABLE READ
트랜잭션이 시작되면 각 트랜잭션이 발생한 시점의 데이터들을 저장한다. 그리고 연산 시 발생한 시점의 데이터만 사용한다. 발생하는 문제로데이터 업데이트할 경우 나중의 트랜잭션만 수행되고, 처음에 시작된 트랜잭션은 무시된다. 또 각 시점별 데이터를 저장하므로 용량 문제가 발생할 수 있다.


SERIALIZABLE
읽기와 수정 모두 동기화를 시켜서 엄격하게 관리한다. 이렇게 할 경우 위의 모든 문제를 해결할 수 있지만 한 작업이 길게 이어지는데 데이터를 오랫동안 사용할 경우 계산낭비가 발생한다.


★.*님의 답변
# 트랜잭션 격리수준(isolation level)이란
- 특정 트랜잭션이 다른 트랜잭션에 변경한 데이터를 볼 수 있도록 허용할지 말지를 결정하는 것

## 격리수준
- READ UNCOMMITTED
- READ COMMITTED
- REPEATABLE READ
- SERIALIZABLE

### READ UNCOMMITTED
- 어떤 트랜잭션의 변경내용이 COMMIT이나 ROLLBACK과 상관없이 다른 트랜잭션에서 보여진다.
- 데이터 정합성에 문제가 많아, 격리수준으로 인정하지 않음

### READ COMMITTED
- 어떤 트랜잭션의 변경 내용이 COMMIT 되어야만 다른 트랜잭션에서 조회할 수 있다.

### REPETABLE READ
- 트랜잭션이 시작되기 전에 커밋된 내용에 대해서만 조회할 수 있는 격리수준

### REPEATABLE READ
- UPDATE 부정합: 변경을 수행할 로우에 대해 잠금이 필요하다.
- Phantom READ: 한 트랜잭션 내에서 같은 쿼리를 두 번 실행했는데, 첫 번째 쿼리에서 없던 유령(Phantom) 레코드가 두 번째 쿼리에서 나타나는 현상을 말한다.

### SERIALIZABLE
- 가장 단순하고 가장 엄격한 격리수준이다.

 



★황*님의 답변
트랜잭션은 데이터의 무모순성을 보장하기 위한 기능입니다. 트랜잭션은 논리적인 작업 셋 자체가 100% 적용되거나(COMMIT) 또는 아무것도 적용되지 않아야 함(ROLLBACK)을 보장해주는 것입니다.
트랜잭션의 격리 수준이란 동시에 여러 트랜잭션이 처리될 때, 특정 트랜잭션이 다른 트랜잭션에서 변경하거나 조회하는 데이터를 볼 수 있도록 허용할지 말지를 결정하는 것입니다.

격리 수준은 다음과 같이 4가지로 정의할 수 있습니다.
READ UNCOMMITTED(커밋되지 않은 읽기)
READ COMMITTED(커밋된 읽기)
REPEATABLE READ(반복 가능한 읽기)
SERIALIZABLE(직렬화 가능)

1. READ UNCOMMITED
각 트랜잭션에서의 변경 내용이 COMMIT이나 ROLLBACK 여부에 상관 없이 다른 트랜잭션에서 값을 읽을 수 있습니다.

따라서 트랜잭션 작업이 완료되지 않았는데도 다른 트랜잭션에서 볼 수 있는 DIRTY READ현상이 발생합니다.
ex: A트랜잭션에서 값을 바꿨으나 아직 커밋되지 않은 상태에서 B트랜잭션이 해당 바뀐 값을 확인할 수 있는 문제가 발생합니다.

2. READ COMMITTED
실제 테이블 값이 아닌 Undo(잘못되었을 경우 데이터가 변경되기 전의 데이터 보관하는 곳) 영역에 백업된 레코드에서 값을 가져옵니다.

하나의 트랜잭션에서 같은 쿼리를 두 번 실행하였을 때 두 실행 조회 값이 달라질 수 있습니다.

정합성 문제가 해결된 것 같지만 부정합 문제가 발생할 수 있습니다.
ex:)A트랜잭션이 작동 도중 B트랜잭션이 해당 값을 조회 한 결과 "P"라는 결과가 나옴. 그 후 A트랜잭션이 커밋이 되면 B트랜잭션에서 조회한 결과 커밋으로 바뀐 결과가 나타남

하나의 트랜잭션 내에서 똑같은 SELECT를 수행했을 경우 항상 같은 결과를 반환해야 하는 정합성 문제에 어긋납니다.

3. REPETABLE READ
트랜잭션이 시작되기 전 커밋된 내용에 대해서만 조회할 수 있는 격리수준입니다.(트랜잭션마다 트랜잭션 ID를 부여하여 트랜잭션 ID보다 작은 트랜잭션 번호에서 변경된 것만 읽습니다.)

부정합이 발생하지 않습니다.

그러나, PHANTOM READ(한 트랜잭션 안에서 일정범위의 레코드를 두번 이상 읽을 때, 첫 번째 쿼리에서 없던 유령 레코드가 두번째 쿼리에서 나타나는 현상)은 여전히 발생합니다.

고립화 수준을 높여 LOCK을 통해 다른 트랜잭션 시점에 다른 데이터가 추가되는 것을 막을 수 있습니다. 그러나 동시성이 저하됩니다.
(오라클은 Lock을 전혀 사용하지 않은 상태서 서로 다른 쿼리를 SCN 확인 과정을 통해 하나의 시점에 존재했던 대상으로만 집계를 수행하는 방법을 사용합니다. 동시성 저하를 하지 않으면서 일관성 유지)


4. SERIALIZABLE
새로운 트랜잭션이 읽은 데이터를 다른 트랜잭션이 갱신하거나 삭제하지 못하게 하고 중간에 새로운 레코드를 삽입 하는것을 막아줍니다.

이 Level에서는 Insert까지 막아줍니다. 다른 트랜잭션에서 이 레코드 변경을 하지 못하게 되기 때문에 동시처리 능력이 떨어지고, 성능 저하, 속도 저하 등이 발생하게 됩니다.



★정*님의 답변
트랜잭션이란, DB에 이루어지는 작업을 의미합니다. 몇 개의 작업이 한 단위를 이룰 수 있고, 이 작업들의 격리 정도를 트랜잭션의 각 격리 수준이라고 합니다.

트랜잭션의 격리 수준은 아래와 같이 4개의 단계가 있습니다.
1. Read Uncommitted
2. Read Commmitted
3. Repeatable Read
4. Serializable

1. Read Uncommitted
커밋되지 않은 트랜잭션까지 읽을 수 있는 격리 수준입니다. 사실상 격리의 개념이 존재하지 않는다고 볼 수 있습니다.


2. Read Committed
커밋된 트랜잭션을 읽을 수 있습니다. 일부 DB에서는 기본적으로 read committed가 기본 격리 단계로 사용됩니다. 데이터를 수정할 때는 수정이 완료될 때까지 lock이 적용되며, 데이터를 읽을 때는 lock이 해제됩니다. 따라서 데이터를 읽는 도중에 데이터가 변경될 수 있는 위험성이 존재합니다.


3. Repeatable Read
데이터가 수정될 때, 조회될 때 모두 lock을 겁니다. 일부 RDBMS의 기본 격리 수준으로 사용되고 있습니다. Phantom read라는 문제점이 발생할 수 있는데, 반복 조회 시 결과 집합이 달라지는 현상을 phantom read라고 합니다.


4. Serializable
가장 엄격한 단계의 격리 수준으로, 완벽한 격리 수준을 나타냅니다. 데이터를 읽거나 쓸 때, 완료될 때까지 lock을 걸게 됩니다. 하지만 이로 인하여 동시성 처리 성능이 떨어지는 문제점이 존재합니다.


★겨*님의 답변
트랜잭션의 격리 수준은 네개로 나눌 수 있다.
1. READ UNCOMMITTED
2. READ COMMITED
3. REPEATABLE READ
4. SERIALIZABLE


아래로 내려갈수록 트랜잭션 간의 고립 정도가 높아지며 성능이 떨어진다. READ UNCOMMITTED 격리수준에서는 어떤 트랜잭션의 변경내용이 Commit 이나 Rollback 과 상관없이 다른 트랜잭션에서 보여진다. 여기선 한 데이터의 값을 변경 후 커밋을 하지 않았는데 다른 트랜잭션에서 해당 데이터를 조회했을 때 변경된 값이 조회되는 더티리드 현상이 발생할 수있다.

READ COMMITTED는 어떤 트랜잭션의 변경 내용이 COMMIT 되어야만 다른 트랜잭션에서 조회할 수 있는데 이는 현재 오라클 DBMS에서 기본으로사용하고 있다.
해당 격리 수준에서는 하나의 트랜잭션 내에서 똑같은 Select 명령을 수행했을 경우 항상 같은 결과를 반환해야 한다는 Repeatable Read 정합성에 문제가 나타날 수 있다. 이를 Non-Repeatable Read 부정합 문제라고 한다.

REPEATABLE READ는 트랜잭션이 시작되기 전에 커밋된 내용에 대해서만 조회할 수 있는 격리 수준이다. MySQL DBMS에서 기본으로 사용하고 있는데, 이는 자신의 트랜잭션 번호보다 낮은 트랜잭션 번호에서 변경된(커밋된) 데이터만 보게 된다. 해당 격리 수준에서는 Update 부정합과 Phantom Read 라는 문제가 발생할 수 있다.

SERIALIZABLE은 가장 단순하고 엄격한 겨리수준이다. 해당 격리 수준에서는 읽기 작업에도 공유 잠금을 설정하게 되고, 다른 트랜잭션에서 해당 레코드를 변경할 수 없다. 이러한 특성 때문에 동시처리 능력이 다른 격리수준보다 떨어지고 성능저하가 발생하게된다.


★서*님의 답변
트랜잭션의 격리 수준이란 동시에 여러 트랜잭션이 처리될 때 특정 트랜잭션이 다른 트랜잭션에서 변경하거나 조회하는 데이터를 볼 수 있도록 허용할지 말지를 결정하는 것으로 네가지로 정의됩니다.


1. READ UNCOMMITTED(커밋되지 않는 읽기)
2. READ COMMITED(커밋된 읽기)
3. REPEATABLE READ (반복 가능한 읽기)
4. SERIALIZABLE(직렬화 가능)


순서대로 1의 수준이 가장 낮고, 4인 직렬화 가능 단계의 수준이 가장 높습니다. 

READ UNCOMMITTED 격리 수준에서는 위 그림처럼 각 트랜잭션에서의 변경 내용이 COMMIT이나 ROLLBACK 여부에 상관 없이 다른 트랜잭션에서 보여지게 됩니다. 하지만 이러한 수준은 트랜잭션에서 처리한 작업이 완료되지 않았음에도 불구하고 다른 트랜잭션에서 볼 수 있게 되는 현상을 야기하고, 이를 더티 리드(Dirty Read) 라고 합니다.

READ COMMITTED 격리 수준은 오라클 DBMS에서 기본적으로 사용되고 있으며 온라인 서비스에서 가장 많이 선택되는 격리 수준입니다. 이 레벨에서는 위 READ UNCOMMITTED 수준에서 발생할 수 있는 더티 리드(Dirty Read)와 같은 현상은 발생하지 않습니다. 어떠한 트랜잭션에서 데이터를 변경하더라도 COMMIT이 완료된 데이터만 다른 트랜잭션에서 조회할 수 있기 때문입니다. 하만 READ COMMITTED 격리 수준에서도 "NON-REPEATABLE READ"라는 부정합 문제가 존재합니다. 즉, 하나의 트랜잭션내에서 동일한 SELECT 쿼리를 실행했을 때 항상 같은 결과를 보장해야 한다는 "REPEATABLE READ" 정합성에 어긋나게 됩니다.

따라서 세번 째 수준인 REPEATABLE READ는 MySQL의 InnoDB 스토리지 엔진에서 기본적으로 사용되는 격리 수준입니다. 이 격리 수준에서는 READ COMMITTED 격리 수준에서 발생하는 "NON-REPEATABLE READ" 부정합이 발생하지 않습니다. 하지만 이러한 격리수준에서도 다른 트랜잭션에서 수행한 변경 작업에 의해 레코드가 보였다가 안보였다가 하는 현상인 PHANTOM READ(PHANTOM ROW)이 발생할 수 있습니다. 

이때문에 네번째 격리수준인 SERIALIZABLE로 설정되면 읽기 작업도 공유 잠금(읽기 잠금)을 획득해야 하며, 동시에 다른 트랜잭션은 그러한 레코드를 변경할 수 없습니다. 즉, 한 트랜잭션에서 읽고 쓰는 레코드를 다른 트랜잭션에서는 절대 접근할 수 없습니다. 이는 팬텀리드 현상을 해결합니다.



★김*님의 답변
격리 수준은 READ UNCOMMITTED(커밋되지 않은 읽기), READ COMMITTED(커밋된 읽기), REPEATABLE READ(반복 가능한 읽기), SERIALIZABLE(직렬화 가능) 으로 정의할 수 있습니다. 순서대로 READ UNCOMMITTED의 격리 수준이 가장 낮고 SERIALIZABLE의 격리 수준이 가장 높습니다.

READ UNCOMMITTED 격리 수준에서는 각 트랜잭션에서의 변경 내용이 COMMIT이나 ROLLBACK 여부에 상관 없이 다른 트랜잭션에서 보여지게 됩니다. 이를 Dirty Read라고 합니다. READ COMMITTED 격리 수준에서는 어떤 트랜잭션에서 변경한 내용이 커밋되기 전까지는 다른 트랜잭션에서 변경 내역을 조회할 수 없습니다.


REPEATABLE READ는 UNDO 영역에 백업된 이전 데이터를 통해 동일한 트랜잭션 내에서는 동일한 결과를 보여줄 수 있도록 보장합니다. 이에 어긋나는 현상을 NON-REPEATABLE READ라고 합니다. 트랜잭션의 격리 수준이 SERIALIZABLE로 설정되면 한 트랜잭션에서 읽고 쓰는 레코드를 다른 트랜잭션에서는 절대 접근할 수 없습니다.

PHANTOM READ는 한 트랜잭션내에서 동일한 쿼리를 두 번 수행했는데, 첫 번째 쿼리에서 존재하지 않던 유령(Phantom) 레코드가 두 번째 쿼리에서 나타나는 현상입니다. 이는 READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ에서 나타날 수 있습니다.


★용*님의 답변
트랜잭션을 T라고 하고 T1의 단위중 갱신구문이 있을때,


READ UNCOMMITTED는
변경된 레코드를 커밋과 롤백 여부에 상관없이 T2에서 조회할 수 있습니다.
이는 해당 격리수준이 언두로그를 활용하지 않고, 디스크에 바로 반영하기 때문입니다.

READ COMMITTED는
변경된 레코드를 커밋되기 전까지 T2에서 조회할 수 없습니다.
이는 해당 격리수준이 언두로그를 활용해 갱신이전 레코드를 유지하기 때문입니다.

REPEATABLE READ는
트랜잭션마다 ID를 부여하여 현 ID보다 작은 ID에서 갱신한 레코드의 갱신 전 레코드를 조회할 수 있게 합니다.

SERIALIZABLE은
동시에 레코드를 조회함은 가능하지만, 갱신은 불가능하며
T1이 조회하면서 T2가 갱신하는 상황도 불가합니다.

다음은, 문제를 나열하고 어떤 수준에 일어나는지 기술하겠습니다.
DIRTY READ는
T2가 T1의 롤백 이전에 레코드를 조회하는 경우에
재개된 T1의 트랜잭션이 커밋되어 T2의 조회가 온전한 조회일수도
커밋되지 않아 온전한 조회가 아닐 수도 있는 현상입니다.
READ UNCOMMITTED에만 발생합니다.

NON-REPETABLE READ는
T2가 여러번 조회하는 사이 T1이 갱신이후 커밋됬다면 T2의 마지막 조회가 일관되지 않은 현상입니다.
T1의 커밋이전까지는 T2가 언두로그를 바라보지만,
T1의 커밋이후 T2가 디스크를 바라보게 되기때문입니다.
READ UNCOMMITTED와 READ COMMITTED에서 발생합니다.
REPEATABLE READ가 극복할 수 있었던 이유는
현 ID보다 작은 ID에서 갱신한 레코드의 갱신전 레코드는 언두로그에 남아있기 때문입니다.

PHANTOM READ는
T2가 여러번 조회하는 사이 T1이 갱신을 했다면
레코드가 변하지는 않지만 추가되거나 삭제될 수 있는 현상입니다.
SERIALIZABLE을 제외한 모든 격리수준에서 발생합니다.
단, InnoDB엔진의 default 수준인 REPEATABLE READ에는 발생하지 않는데,
Gap lock을 사용해 레코드의 일정 구간 자체에 락이 걸려 T1의 갱신 행위가 이뤄지지 않기 때문입니다.

+ Recent posts