본문 바로가기

CS 과목(CS科目)/데이터 베이스(データベース)

20. MVCC - Part 2

Locking Read

이번 시간에는 MySQL에서는 Lost Update 문제를 어떻게 해결해야 하는지에 대해 알아 보자. 

Locking Read는 MySQL에서만 사용하는 개념이다.

보통, read(x)를 하기 위해서는 SELECT balace from account where id = x 라는 SQL문을 작성을 할 것이다.

MySQL에서는 Lost Update문제를 해결하기 위해서 FOR UPDATE 문을 추가적으로 개발자가 작성을 하여서, Write_Lock

을 취득하게 하여 값을 read해야 한다. 

위와 같이 MySQL 세계관에서는 데이터를 읽을 때(read할 때), Lost Update 문제를 해결하기 위해 write lock을 취득한 후에

값을 읽어 들이는데, 이러한 read를 Locking Read라고 한다. 

( Locking Read가 어떻게 MySQL에서 Lost Update를 해결하는지는 아래를 더 봐야 한다.)

트랜잭션 1에서도 x를 읽기 위해서는 똑같이 FOR UPDATE문을 써줌으로서, write lock을 취득한 후에 읽는다. 

그러나, x에 대한 write lock은 이미 트랜잭션 2에서 가지고 있기에 트랜잭션 1은 이 시점에서 block된 상태로 대기 상태가 된다. 

 

x에 대한 write lock이 반환되었으므로, 드디어 트랜잭션 1에서 x에 대한 값을 읽어 들일 수가 있다.

이전 시간에서 우리는 repeatable read level에서는 [트랜잭션이 시작되는 시점에서의 가장 최근의 commit된 데이터

(x=50)]를 읽어 들인다고 배웠다.

그러나 MySQL에서는 트랜잭션이 어떠한 isolation level이든 상관없이, Locking Read 상태에서는 가장 최근의 commit된

데이터를 읽는다. 고로 read(x)는 x=50이 아닌 x=80을 읽어 들인다.    

Locking Read는 위 그림과 같이 FOR UPDATE와 FOR SHARE로 구현이 된다.

FOR UPDATE : read/write lock, 2개의 lock을 획득.

FOR SHARE : read lock만을 획득

-> Locking Read라는 용어 자체는 MySQL에서만 사용이 되지만, FOR UPDATE, FOR SHARE문은 다른 RDBMS에세도 사용이 된다.(그러나 동작 방식이 MySQL과는 다르다. 자세한 건 밑에서 자세히 설명하겠다.)

 

repeatable read level에서 발생하는 write screw 문제

정상적인 결과는 (x,y)=(20,30) or (30,20)중 하나가 되어야 하는데, 결과값이 왜곡(skew)이 되었다.

즉, write skew가 발생을 했다.

MVCC의 repeatable read level에서는 이와 같은 write skew문제가 발생을 할 수가 있다.

MySQL과 Postgre SQL에서 이 write skew 현상을 어떻게 해결이 가능한지를 살펴 보자. 

 

MySQL에서의 write skew 해결법

Locking Read를 사용하면 된다. 

MySQL의 Locking Read는 가장 최근에 commit된 데이터를 읽기 때문에 트랜잭션2의 read(x)는 20을 읽게 된다. 

위 그림의 최종 결과는 (x,y)=(20,30)이므로 write skew문제가 해결이 되었다.

그러면, Postgre SQL은 write skew 문제를 어떻게 해결하는지 알아 보자. 

Postgre SQL에서의 write skew의 해결법

결과부터 말을 하면, Postgre SQL에서도 똑같이 FOR UPDATE, FOR SHARE을 사용하여 write skew를 해결한다.

그러나, 그 해결되는 실행 과정이 MySQL과는 다르다. 

트랜잭션1이 commit되기 전까지는 MySQL과 Postgre SQL의 실행 과정은 같다.

 

Postgre SQL의 repeatable read level에서는 같은 데이터를 먼저 update한 tx가 commit되면, 나중에 실행되는 tx는 rollback

이 된다 라는 규칙을 저번 시간에 학습을 하였다. 

고로 트랜잭션 2의 read(x)가 실행이 되는 시점에서 abort가 발생을 하여, roll back이 일어난다.

 

rollback이 완료된 후, 트랜잭션 2를 다시 실행을 시키면 write skew문제는 해결이 된다. 

이와 같이 Postgre SQL에서도 write skew문제를 해결하기 위하여 for update을 사용하여 write skew문제를 해결

을 하였지만,  그 해결되는 과정이 MySQL과는 차이가 있다는 것을 유념해 두자.  

이번에는 For Share이 사용되어 write skew가 해결되는 예제를 살펴보자.

for share은 read하기 위한 lock을 취득하기 위한 sql문이다.

트랜잭션2의 read(x)는, 트랜잭션 1에서 이미 x에 대한 lock을 취득하고 있기 때문에, block처리가 된다.

(여담으로, MVCC는 기본적으로 read에 대한 lock을 필요로 하지 않는다.)

 트랜잭션 1의 commit이 끝나고 block 처리가 됐던 read(x)를 다시 실행을 하려고 해도, Postgre SQL에서는 roll back이 일

어나므로 write skew 문제는 발생을 하지 않는다. 

isolation level을 serializable로 설정하여 write skew문제 해결

serialiable level은 그 어떠한 이상 현상도 일어 나지 않기 때문에 write skew문제를 발생시키지 않는다. 

그러나 RDBMS마다 serializable level에서의 동작 방식이 살짝 다르다고 한다. 

(이 부분은 강의자도 잘 모른다고 걍 넘어가심)