[Database] Transaction Isolation Level

Dabi·2022년 4월 5일
5

데이터베이스

목록 보기
5/10


이번 포스팅에서는 트랜잭션의 격리수준에 대한 내용을 담고 있습니다.



[Intro]

미국의 서부 개척 시대에 주점들은 손님을 더 많이 끌어들이기 위해 공짜 점심 이벤트를

여는 문화가 있었다고 합니다. 하지만 이내 몰려든 손님들은 자신들이 마시는 술값점심값

포함되어 있다는 것을 깨닫게 되어 "공짜 점심은 없다" 라는 격언이 등장하게 되었습니다.



술집을 운영하는 사장의 입장에선 손님들을 끌어들이기 위해 점심을 무료로 제공하자니

술값을 올려야하고, 점심값을 받자니 마케팅 효과가 떨어지게 되는것이죠.



이러한 Trade-Off는 앞서 포스팅했던 트랜잭션의 Isolation Level(격리 수준)에서도

나타납니다. 격리 수준을 높이면 접근 제어의 수준은 강해지지만 동시처리 성능이 낮아지고,

격리 수준을 낮추면 동시처리 성능은 올라가지만 접근 제어의 수준이 약해집니다.

이번시간에는 이런 트랜잭션의 격리수준은 단계별로 어떻게 이루어지고, 각각의 단계에 따라

어떠한 특징을 보이는지 알아보도록 하겠습니다.

[Concept]

트랜잭션 격리수준(Isolation Level) 이란 동시에 여러 트랜잭션이 처리될 때,

트랜션이 얼마나 서로 얼마나 고립되어 있는지를 나타내는 것입니다.


쉽게 말해, 특정 트랜잭션다른 트랜잭션변경한 데이터를 볼 수 있도록

허용할지 말지를 결정하는 것이라고 할 수 있습니다.

격리수준은 크게 아래의 4개로 나뉩니다.

  • READ UNCOMMITTED

  • READ COMMITTED

  • REPEATABLE READ

  • SERIALIZABLE

하나씩 알아보도록 하겠습니다.

LV.0 READ UNCOMMITTED


커밋되지 않은 데이터에 접근이 가능한 수준

위 그림의 순서는 다음과 같습니다.

1. 트랜잭션 1  START

2. 트랜잭션 2  START

3. 트랜잭션 1 이  ID = 1, VAL = "MIN"인 데이터를 KIM으로 변경

4. 트랜잭션 2 가 ID = 1 을 조회, VAR = "KIM"이 조회됨

5. 트랜잭션 1 Commit , 트랜잭션 2 Commit

위 그림과 같이 Transaction 1 이 수행이 시작되어 1번 인덱스에 저장된 데이터를 업데이트하고

Commit을 통해 트랜잭션을 완료하기 전에 다른 트랜잭션이 1번 아이디의 데이터에 접근할

수 있는 상황을 말합니다.



이러한 상황에서 발생할 수 있는 문제로는 Dirty Read 가 있습니다.


[Dirty Read]

  • UPDATE 반영 전에 읽는 오류

    • 순서 5에서 오류가 생겨 롤백이 되었다고 가정한다면, ID = 1은 다시 MIN이
      되어야 합니다.

    • 하지만 트랜잭션 2는 롤백되는 시점에 조회가 끝나버렸기 때문에 여전히
      VAR = 'KIM'으로 인식하게 되는 문제가 발생합니다.


  • INSERT 반영 전에 읽는 오류

    • 트랜잭션 1이 특정 데이터를 INSERT합니다.

    • 트랜잭션 2가 해당 데이터를 읽고 로직을 수행합니다.

    • 트랜잭션 1 수행 중 오류가 생겨 Rollback합니다. INSERT한 데이터가 삭제됩니다.

    • 그러나 트랜잭션 2는 이미 로직을 수행한 상태이기 때문에 RollBack되어 사라진
      데이터를 읽고 수행한 상태여서 없는 데이터를 읽게됩니다.

LV.1 READ COMMITTED

특정 쿼리가 요청되는 시점에 어떤 트랜잭션에 의해 이미 커밋된 데이터들만 조회할 수 있는 수준

순서

1. 트랜잭션 1 START

2. 트랜잭션 1이 ID = 1인 데이터의 VALUE를 KIM으로 변경했다. 

3. 트랜잭션 2 START

4. 트랜잭션 2가 ID = 1인 데이터를 조회한다. MIN이 검색된다. 

5. 트랜잭션 1 Commit & END

6. 트랜잭션 2가 ID = 1인 데이터를 조회한다. KIM이 검색된다. 

7. 트랜잭션 2 커밋을 하고 종료한다.

커밋된 데이터만 읽어 오기 때문에 LV.0과의 차이점은 첫번째 SELECT문에서

KIM이 아닌 MIN이 조회된다는 것이 가장 큰 차이점입니다.

하지만 LV.1에서는 Non-Repeatable Read 문제가 발생할 수 있습니다.

[Non-Repeatable Read]

하나의 트랜잭션이 같은 값을 조회할 때 다른 값이 검색되는 현상입니다.

위의 그림에서 트랜잭션 2의 첫 번째 조회에는 MIN이, 두 번째 조회에는 KIM이 검색되고 있습니다.

이와 같이 하나의 트랜잭션내에서 같아야할 정보가 달라지게 되는 문제가 발생하는 것이

Non-Repeatable Read입니다.



LV.2 REPEATABLE READ



트랜잭션이 시작되고 종료되기 전까지 한 번 조회한 값은 계속 같은 값이 조회되는 격리 수준

REPEATABLE READ트랜잭션 시작 전에 커밋된 내용에 한해서만 조회하는 방식의 격리수준입니다.

데이터를 변경하려고 하면 UNDO영역에 백업해두고 실제 레코드를 변경하게 됩니다.

Lv.2에서는 Non-Repeatable Read는 발생하지 않습니다.


1. 트랜잭션 1을 시작한다.

2. 트랜잭션 1이 ID = 1인 데이터를 조회한다. 

3. 트랜잭션 2가 시작되었다. 

4. 트랜잭션 2가 ID = 1인 데이터를 KIM으로 변경한다. 

5. 트랜잭션 1이 ID = 1인 데이터를 조회한다. 트랜잭션 2의 변경 내역이 보이지 않는다. 

6. 트랜잭션 2가 ID = 2인 데이터를 삽입 후 commit하여 트랜잭션을 종료한다. 

7. 트랜잭션 1이 ID = 2인 데이터를 조회한다. 데이터가 정상적으로 확인된다. 

8. 트랜잭션 1이 종료된다.

이 격리 수준에서는 UPDATE한 데이터에 대해서는 정합성이 보장됩니다.

하지만 INSERT/DELETE에 대해서는 위 그림과 같이 보장되지 않음을 알 수 있습니다.



이 때문에 이 격리 수준 이하에서는 Phantom Read문제가 발생합니다.


[Phantom Read]


Phantom Read란 마치 유령 보는 것처럼 있던 데이터가 사라지거나 없던 데이터가 생기는 현상을

말합니다. 바로 위 예제의 순서 7에서 트랜잭션 1이 ID = 2인 데이터를 조회하고 있다.

ID = 2는 트랜잭션 1이 시작하던 시점에선 테이블에 없던 데이터입니다.



LV.3 SERIALIZABLE



트랜잭션이 특정 테이블을 읽으면 다른 트랜잭션은 그 테이블의 데이터를 접근할 수 없는 수준

가장 강력한 격리 수준이며 데이터 정합성을 가장 잘 보장합니다.

그러나 동시 처리 성능이 가장 떨어집니다.

이 격리 수준에서는 위에서 언급했던 Dirty Read, Non-Repeatable Read,

Phantom Read 와 같은 정합성 문제가 전혀 발생하지 않습니다.



[Conclusion]

그렇다면 어떤 격리수준으로 설정해주는 것이 적합할까요?

정해진 답은 없습니다.

데이터 정합성과 동시 처리 성능은 반비례하기 때문에 어떤 격리 수준이 무조건 좋다 나쁘다를

말하기는 어렵습니다. 데이터를 어떻게 다룰지에 따라 적절한 전략을 선택하는 것이 중요합니다.

profile
논리적인 사고와 추론을 지향합니다.

3개의 댓글

comment-user-thumbnail
2022년 4월 6일

트랙잭션은 알고 있었지만 격리 수준이 있다는 건 몰랐는데 유용한 글이네요!

답글 달기
comment-user-thumbnail
2022년 4월 6일

트랜잭션 격리수준에 대해서 몰랐는데 덕분에 알아갑니다!!

답글 달기
comment-user-thumbnail
2022년 4월 6일

트랜잭션의 격리수준에 대해서 알수있었습니다! 유익한 포스팅 감사합니다!

답글 달기