본문 바로가기

Database

[Database] 트랜잭션 격리 수준 (Transaction Isolation Level)

반응형

트랜잭션 격리 수준 (Transaction Isolation Level) 이란,

동시에 여러 트랜잭션이 처리될 때 트랜잭션끼리 서로 얼마나 고립(isolation) 되어 있는지를 나타낸다.

즉, 하나의 트랜잭션이 다른 트랜잭션에 변경한 데이터를 볼 수 있도록 허용할지 말지를 결정한다.

 

우선 Isolation Level 에 대해 알기 전에 알아야 할 개념이 있다.

바로 Consistent Read 이다.

 

Consistent Read 란, 말그대로 "일관된 읽기" 로 생각하면 된다.

SELECT 문 실행 시 동시에 다른 트랜잭션에서 데이터를 변경하더라도 Undo Log 에 변경 전의 데이터(snapshot) 를 생성하고,

해당 시점의 snapshot 을 가져와 동일한 결과를 반환하여 일관성을 보장하기 위한 방법이다.

 

이를 MVCC 기법이라고도 하며,  자세한 내용은 아래 포스팅에서 확인 가능하다.

 

https://ryean.tistory.com/63

 

[Database] MVCC (Multi Version Concurrency Control) - 다중 버전 동시성 제어

데이터베이스에서는 여러 사용자가 동시에 접근하여 데이터를 읽고, 변경할 수 있는 동시성이 중요하다. 또한, 동시성과 함께 데이터의 일관성이 보장되어야한다. 이 동시성을 제어하고 일관성

ryean.tistory.com

 

 

Isolation Level 종류에는 총 4가지가 있다.

 ν  Read Uncommitted (커밋되지 않은 읽기)

 ν  Read Committed (커밋된 읽기)

 ν  Repeatable Read (반복 가능한 읽기)

 ν  Serializable (직렬화 가능)

 

Isolation Level Dirty Read Non-Repeatable Read Phantom Read
Read Uncommitted 발생 발생 발생
Read Committed X 발생 발생
Repeatable Read X X 발생 (MySQL InnoDB 제외)
Serializable X X X

 

 

Read Uncommitted


 ν 가장 낮은 격리 수준이다.

 ν 아직 commit 되지 않은 데이터를 다른 트랜잭션이 조회(SELECT) 하는 것을 허용한다.

 ν 이로 인해 정합성에 문제가 있으며, Dirty Read 가 발생한다. (Non-Repeatable Read, Phantom Read 도 모두 발생한다.)

 ν SQL 표준에서 Read Uncommitted 사용을 권하지 않는다. 

 

 

 Dirty Read

  ν 아직 commit 되지 않은 하나의 트랜잭션의 임시 데이터(Dirty) 를 읽을 수 있을 수 있는 현상을 말한다.

 

아래와 같은 UserArea 라는 테이블이 존재한다고 하자.

id name area
1 순애 서울
2 철수 인천

 

그리고 A 라는 유저가 아래와 같은 쿼리를 실행했다고 하자.

-- SQL Server
-- A 유저
set transaction isolation level read uncommitted;

begin transaction;

update UserArea
set area = '경기'
where name = '순애';

 

 

아직 A 유저의 트랜잭션이 commit 되지 않은 상태에서 B 유저가 해당 데이터를 조회했다.

-- SQL Server
-- B 유저
set transaction isolation level read uncommitted;

select * from UserArea where name = '순애';

 

 

그러면 아래와 같이 commit 되지 않은 데이터가 조회가 될 것이다.

id name area
1 순애 경기
2 철수 인천

 

 

이처럼 commit 되지 않은 더티상태의 데이터를 읽을 수 있는 현상을 Dirty Read 라고 한다.

 

여기에서 A 유저가 commit 을 하면 데이터에 문제가 없을 수 있겠지만 만약 rollback 을 한다면?

area 는 '서울' 로 rollback 이 되게 되는데, B 유저에게는 '경기' 로 조회가 되므로 데이터의 정합성에 문제가 발생할 수 있게 되는 것이다.

 

 

 

Read Committed


 ν Oracle, SQL Server기본 트랜잭션 격리 수준이다.

 ν Read Committed 부터 Consistent Read 개념을 사용한다.

 ν 아직 commit 되지 않은 데이터를 읽을 수 없으며, commit 이 이루어진 트랜잭션만 조회(SELECT) 하는 것을 허용한다.

 ν 그러나, 하나의 트랜잭션 내에서 조회(SELECT) 결과가 다를 수 있는 Non-Repeatable Read 이 발생한다.

 

 

  Non-Repeatable Read

  ν 하나의 트랜잭션에서 같은 쿼리를 두 번 수행할 때 그 사이에 다른 트랜잭션 값을 수정 또는 삭제하면서 두 쿼리의 결과가 상이하게 나타나는 현상이다.

 

 

아래와 같은 UserArea 라는 테이블이 존재한다고 하자.

id name area
1 순애 서울
2 철수 인천

 

 

그리고 A 라는 유저가 아래와 같은 SELECT 문을 실행했다고 하자.

-- SQL Server
-- A 유저
set transaction isolation level read committed;

begin transaction;

select * from UserArea where name = '순애';

 

 

그러면 아래와 같이 name = '순애' 의 데이터가 조회가 될 것 이다.

id name area
1 순애 서울

 

 

A 유저가 아직 commit 하지 않은 상태에서 B 유저가 아래와 같이 '순애' 의 area 컬럼을 변경 후 commit 했다고 하자.

-- SQL Server
-- B 유저
set transaction isolation level read committed;

begin transaction;

update UserArea
set area = '경기'
where name = '순애';

commit;

 

 

이 상태에서 A 유저가 아까의 SELECT 문을 동일하게 실행하면 어떻게 될까?

 

id name area
1 순애 경기

 

 

위와 같이 하나의 트랜잭션 내에서 동일한 SELECT 문을 날렸을 경우,  조회 결과가 달라지는 모습을 볼 수 있다.

이 현상을 Non-Repeatable Read 라고 한다.

 

 

 

Repeatable Read


 ν  MySQL기본 트랜잭션 격리 수준이다.

 ν  하나의 트랜잭션 내에서 SELECT 조회 결과 값이 같음을 보장한다.

 ν  하지만, 하나의 트랜잭션 내에서 SELECT 조회 결과 수가 달라질 수 있는 Phantom Read 이 발생한다.

 

 

   Phantom Read

     ν 하나의 트랜잭션 내에서 SELECT 조회 결과 수가 달라질 수 있는 현상이다.

     ν MySQL InnoDB 스토리지 엔진에서는 발생하지 않는다. (이유는 하단에)

 

 

아래와 같은 UserArea 라는 테이블이 있다.

id name area
1 순애 서울
2 철수 인천

 

 

A 유저가 UserArea 의 레코드 수를 조회를 하니 총 2건이 조회될 것이다.

-- SQL Server
-- A 유저
set transaction isolation level repeatable read;

begin transaction;

	select count(*) from UserArea;
    
    
    
---------------
row_count
---------------
2

 

A 유저가 commit 을 안한 상태에서 B 유저가 UserArea 에 데이터를 Insert 했다고 하자.

-- SQL Server
-- B 유저
set transaction isolation level repeatable read;

begin transaction;

	insert into UserArea values (3,N'영희',N'대전');

commit;

 

 

이 때, A 유저가 동일한 쿼리를 날리면 총 3건의 결과가 조회될 것이다.

-- SQL Server
-- A 유저

select count(*) from UserArea;
    
    
---------------
row_count
---------------
3

 

이처럼 하나의 트랜잭션 내에서 SELECT 조회 갯수가 달라질 수 있는 현상을 Phantom Read 라고 한다.

 

 

 

※ Non-Repeatable Read 와 Phantom Read 의 차이

  ν  Non-Repeatable Read : 하나의 트랜잭션 내에서 조회 결과 레코드 값이 다르게 조회될 수 있음

  ν  Phantom Read : 하나의 트랜잭션 내에서 조회 쿼리 결과 레코드 수가 다르게 조회될 수 있음

 

 

 

※ InnoDB 스토리지 엔진에서 Phantom Read 가 발생하지 않는 이유

일반적으로, 다른 데이터베이스는 Record Lock 을 이용하여 잠그지만, MySQL InnoDB 에서는 Next-Key Lock 을 이용한다. 

특정 레코드에 대해서만 Lock 을 걸지 않고, 검색하고자 하는 범위 내에서 Gap Lock 을 걸어버리기 때문에 중간에 특정 데이터가 추가 혹은 삭제되어 발생하는 Phantom Read 를 방지해준다.

 

ν  Record Lock

  ㅁ 레코드를 잠그는 Lock 이다.

 

ν   Gap Lock

  ㅁ 레코드 사이의 간격을 잠그는 Lock 이다.

  ㅁ 특정 레코드 간격에 무언가 삽입되거나 삭제되는 등의 작업을 방지할 수 있다.

 

ν  Next-Key Lock

  Record Lock 과 Gap Lock 을 모두 합쳐놓은 형태의 Lock 이다.

  ㅁ SELECT 시 조회된 레코드와 해당 레코드 앞의 갭에 Lock 을 걸어 조회된 레코드와 레코드 앞에 새로운 데이터를 추가할 수 없도록 한다.

  ㅁ 또, 조회된 레코드 중 마지막 레코드 뒤의 갭에 Lock 을 걸어 마지막 레코드 뒤에도 다음 데이터를 추가할 수 없도록 Lock 을 건다.

 

 

 

Serializable


ν  가장 높은 격리 수준이다.

ν  Consistend Read 를 사용하지 않고, SELECT 문장이 사용되는 모든 데이터에 항상 S-Lock 을 걸고 데이터를 조회하게 하여 정합성을 보장한다.

ν  그만큼 성능이 저하되어 거의 사용하지 않는다.

 

 

 

트랜잭션간 고립이 높아지면 성능이 떨어지는 것이 일반적이다.

동시성이 높아지면 데이터 무결성이 낮아지고, 데이터 무결성이 높아지면 동시성이 떨어지게 된다.

 

고로, 상황에 맞게 알맞은 트랜잭션 격리 수준을 알맞게 설정해야한다!

 

 

반응형