1060 단어
5 분
MVCC 그리고 PostgreSQL과 MySQL의 차이점
MVCC
MVCC는 다중 버전 동시성 제어의 약자이다. “기존 데이터를 덮어쓰기” 대신 “새 데이터를 쌓아올린다”로 요약할 수 있다.
그러니까 창팝으로 비유하자면…
A교실에서 시험 치면 강제 -50점 B교실에서 시험 치면 강제 +50점 근데 몇 개월 전에 이 사실에 대해 모른 채로 A교실에서 시험 치기로 한 거임 교실을 바꾸려면 내년을 기약하고 똑같이 B교실이 +50점 줄지 모르는 상황 이 형평성에 가만히 있으면 정당한거냐? -메벤남
그냥넣어보고싶었음
이해가하나도안되잖아쿼리슝좍아
Git으로 설명해보자.
- 일단 main 브랜치에서 dev 브랜치를 딴다. (
BEGIN) - 거기서 작업을 잔뜩 한다. (
BEGIN이후 쿼리) - 이제 작업사항들을…
- main에 머지하거나(
COMMIT) - 버린다(
ROLLBACK)
- main에 머지하거나(
PostgreSQL의 MVCC 구현
어 코끼리는 짱커 그래서 디스크 더 쓸 거야
순서대로 알아보자면
BEGIN- 대충 뭔가 어마무시하게 많은 쿼리들
UPDATE: 쓰려는 원본 테이블 대신 임시 튜플을 만들고, 그곳에 UPDATE한다SELECT: 원본 테이블과 임시 튜플(있으면)에서 찾는다
- 이제 다 끝나고…
ROLLBACK: 임시 튜플을 버린다COMMIT: 임시 튜플로 원본 테이블의 튜플을 교체한다(레퍼런스 교체 느낌으로 빠르다!)
그렇게 되면, 임시 튜플이나 원본 튜플들은 레퍼런스 없이 떠돌게 된다. 이는 VACUUM 시 GC된다.
이 구현의 장점은…
- 어마무시하게 원자적이다. 레퍼런스 바꾸기 딸깍ㅋㅋ
SELECT가 여러 번 있어도 용량이 커지지 않는다- 락도 안 걸린다!
한편 단점은…
UPDATE쿼리 많으면 산으로 간다. 디스크 용량 3배 사용 이벤트!
MySQL의 MVCC 구현

순서대로 알아보자면
BEGIN- 대충 뭔가 많은 쿼리들
UPDATE: 원래 데이터를 undo log에 백업해두고, 원본 테이블을 바로 수정한다SELECT: 현재 트랜잭션 격리 수준에 따라, undo log를 참고해서 적절한 버전의 데이터를 조회한다
- 이제 다 끝나고…
ROLLBACK: undo log에 있는 원래 데이터로 복구한다COMMIT: 변경사항을 확정한다. undo log는 더 이상 필요 없어지면 purge 스레드가 정리한다
undo log에는 두 종류가 있다:
- insert undo log:
INSERT때 기록. 트랜잭션 커밋되면 바로 버려도 됨 - update undo log:
UPDATE/DELETE때 기록. MVCC를 위해 커밋 후에도 당장 안 지울 수도 있음
트랜잭션 격리 수준별 동작 방식:
이 구현의 장점은…
- 디스크 용량을 PostgreSQL보단 적게 쓴다. 원본을 바로 갈아치우니까
UPDATE가 많아도 튜플이 쌓이지 않는다
한편 단점은…
- undo log 관리가 복잡하다. purge 스레드가 바쁘게 돈다
- 롤백 시 undo log를 뒤져서 원복해야 하므로 오래된 트랜잭션일수록 롤백 비용이 크다
SELECT가 오래된 undo log까지 뒤져야 하면 느려질 수 있다, 위 단점과 시너지
그래서 뭐가 더 좋은데?
둘 다 정답은 없다. 트레이드오프가 있을 뿐.
| 항목 | PostgreSQL | MySQL |
|---|---|---|
| 저장 방식 | 새 튜플 추가 (append-only) | 원본 수정 + undo log |
| 디스크 사용량 | UPDATE 많으면 죽을게 | 상대적으로 안정적 |
| SELECT 성능 | 어 형이야 형은 락 거는 법 몰라 | 격리 수준에 따라 다름 |
| VACUUM / Purge | VACUUM 필요 (안 한다고? 그럼죽어) | purge 스레드가 자동 처리 |
| 롤백 속도 | 임시 튜플 삭제만 하면 끝 | undo log 뒤져서 복구해야 함 |
| 원자성 | 레퍼런스 교체로 딸깍 | undo log 기반 복구 |

요약
- PostgreSQL: 읽기 성능이 중요하고, 디스크 넉넉할 때. MVCC가 진짜로 “쌓아올린다”에 가깝다
- MySQL: 읽기/쓰기 밸런스가 중요하고, 디스크를 아껴야 할 때. Undo log로 타협한 MVCC