728x90
반응형
MVCC는 commit된 데이터만 읽는다.
- 데이터를 읽을 때 특정 시점 기준으로 가장 최근에 commit된 데이터를 읽는다.
- 데이터 변화 이력을 관리한다.
- read와 write는 서로를 block하지 않는다.
MVCC 예제
x=10
Transaction1
- x를 읽는다.
Transaction2
- x를 50으로 바꾼다.
시작
- Transaction2에서 x를 50으로 바꾼다. write(x=50)
- 트랜잭션 2만 알 수 있는 공간에 x=50을 적는다.
- Transaction1에서 x를 읽는다. read(x) → 10
- Transaction2 commit → x = 50
- Isolation Level이 read committed라면
- Transaction1에서 x를 읽는다. read(x) → 50
- Isolation Level이 repeatable read라면
- Transaction1에서 x를 읽는다. read(x) → 10
MySQL에서 lost update 해결
x=50, y=10
Transaction1
- x가 y에 40을 이체한다.
Transaction2
- x에 30을 입금한다.
시작
- Transaction2에서 x를 읽는다. read(x) → 50
- SELECT balance FROM account WHERE id = ‘x’ FOR UPDATE
- read를 하면서 write lock을 취득할 수 있다.(Locking read)
- Transaction1에서 x를 읽는다. read(x) → 50
- SELECT balance FROM account WHERE id = ‘x’ FOR UPDATE
- read를 하면서 write lock을 취득할 수 있다.(Locking read)
- Transaction2에서 x에 30을 더한다. write(x=80)
- Transaction2 commit
- Transaction1에서 x를 읽는다. read(x) → 80
- 원래 repeatable read라면 트랜잰셕 시작전 값인 50을 읽어야 하는데, 트랜잭션2가 commit된 80을 읽고있다.
- locking read는 가장 최근의 commit된 데이터를 읽는다.
- Transaction1에서 x에 40을 빼준다. write(x=40)
- Transaction1에서 y를 읽는다. read(y) → 10
- SELECT balance FROM account WHERE id = ‘y’ FOR UPDATE
- read를 하면서 write lock을 취득할 수 있다.(Locking read)
- Transaction1에서 y를 50으로 바꾼다. write(y=50)
- Transaction1 commit
핵심
- MySQL은 repeatable read라서 해결을 못했는데, locking read를 이용해 해결.
- SELECT … FOR UPDATE; → write lock 획득
- SELECT … FOR SHARE; → read lock 획득
repeatable read에서 write skew 문제
x=10, y=10
Transaction1
- x와 y를 더해서 x에 쓴다.
Transaction2
- x와 y를 더해서 y에 쓴다.
정상적으로 동작한다면 최종 결과는
- x = 20, y = 30
- x = 30, y = 20
둘 중 하나가 되어야 한다.
시작
- Transaction1에서 x를 읽는다. read(x) → 10
- Transaction1에서 y를 읽는다. read(y) → 10
- Transaction2에서 x를 읽는다. read(x) → 10
- Transaction2에서 y를 읽는다. read(y) → 10
- Transaction1에서 x에 10을 더해준다. write(x=20)
- x lock 획득
- Transaction2에서 y에 10을 더해준다. write(y=20)
- y lock 획득
- Transaction1 commit
- Transaction2 commit
- 최종 결과는 x = 20, y = 20이 나온다.
MySQL에서 write skew 문제해결
x=10, y=10
Transaction1
- x와 y를 더해서 x에 쓴다.
Transaction2
- x와 y를 더해서 y에 쓴다.
시작
- Transaction1에서 x를 읽는다. read(x) → 10
- SELECT balance FROM account WHERE id = ‘x’ FOR UPDATE
- Locking read 획득
- Transaction2에서 x를 읽으려고 한다. read(x)
- SELECT balance FROM account WHERE id = ‘x’ FOR UPDATE
- Locking read 획득을 기다림.
- Transaction1에서 y를 읽는다. read(y) → 10
- SELECT balance FROM account WHERE id = ‘y’ FOR UPDATE
- Locking read 획득
- Transaction1에서 x에 10을 더해준다. write(x=20)
- Transaction1 commit
- Transaction1에서 획득한 lock 반환
- Transaction2에서 x를 읽는다. read(x) → 20
- SELECT balance FROM account WHERE id = ‘x’ FOR UPDATE
- Locking read 획득.
- Transaction2에서 y를 읽는다. read(x) → 10
- SELECT balance FROM account WHERE id = ‘y’ FOR UPDATE
- Locking read 획득.
- Transaction2에서 y에 20을 더해준다. write(y=30)
- Transaction2 commit
- x = 20, y = 30
출처
https://www.youtube.com/watch?v=wiVvVanI3p4&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=19
https://www.youtube.com/watch?v=-kJ3fxqFmqA&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=20
728x90
반응형
'DataBase' 카테고리의 다른 글
[DataBase] Transactional Isolation Level (0) | 2023.08.03 |
---|---|
[SQL] DDL(Data Define Language) (0) | 2023.03.08 |
[DB] 데이터베이스 기본개념 (0) | 2023.03.08 |