VACUUM과 Tuple을 이해하기 이전에 반드시 먼저 알아야 할 내용이다.

 

MVCC (Multi-Version Concurrency Control, 다중 버전 동시성 제어)는 PostgreSQL이 동시성을 관리하는 핵심 메커니즘이다.

  • 트랜잭션이 서로 간섭하지 않도록 과거 버전을 유지하여, 락(Lock) 없이 동시성을 보장
  • 읽기(SELECT)와 쓰기(UPDATE, DELETE)가 충돌하지 않음
  • VACUUM과 함께 관리되며, 불필요한 데이터(Dead Tuple)를 자동 정리

 

1️⃣ MVCC란?

  • PostgreSQL에서는 데이터 변경 시 기존 데이터를 덮어쓰지 않고 새로운 버전을 생성
  • 과거 데이터를 유지하면서 새로운 트랜잭션이 최신 데이터를 조회할 수 있음
  • 트랜잭션 격리 수준에 따라 과거 데이터 접근 방식이 달라짐

기존의 단일 버전 모델과의 차이점

전통적인 모델 MVCC (PostgreSQL)
데이터 수정 시 즉시 반영 데이터 수정 시 새로운 버전 생성
SELECT 시 다른 트랜잭션과 충돌 가능 SELECT 시 과거 버전을 참조하여 충돌 방지
Lock 기반 동시성 제어 Lock 없이 일관성 유지 가능

 

2️⃣ PostgreSQL의 MVCC 동작 원리

PostgreSQL에서 INSERT, UPDATE, DELETE가 실행될 때 어떻게 동작하는지를 살펴보자.

 

(1) INSERT (새로운 Tuple 생성)

INSERT INTO user (id, name) VALUES (1, 'Alice');

컬럼이 'id(식별번호)', 'name(이름)'을 가진 'user(사용자)' 라는 테이블에 '1'과 'Alice'를 입력한다.

 

✅ 새로운 Tuple(레코드)가 Page(8KB 블록) 내부에 저장되며, 트랜잭션 정보를 포함한다.

id name xmin (생성 트랜잭션 ID) xmax (삭제 트랜잭션 ID)
1 Alice 1001 NULL
  • xmin: 이 튜플을 생성한 트랜잭션 ID (1001)
  • xmax: 이 튜플이 삭제될 트랜잭션 ID (NULL이면 아직 삭제되지 않음)

(2) UPDATE (새로운 Tuple 생성 & 기존 Tuple은 Dead Tuple)

UPDATE user SET name = 'Alice Smith' WHERE id = 1;

식별자(id)가 '1'인 행의 이름(name)의 값을 'Alice' 에서 'Alice Smith'로 변경함.

 

✅ PostgreSQL에서 UPDATE는 기존 데이터를 변경하지 않고 새로운 버전을 생성함.

id name xmin (생성 트랜잭션 ID) xmax (삭제 트랜잭션 ID)
1 Alice 1001 1002
1 Alice Smith 1002 NULL
  • 기존 버전의 xmax = 1002 (이제 이 튜플을 읽을 수 없음)
  • 새로운 버전이 xmin = 1002로 추가됨

UPDATE는 DELETE + INSERT와 유사한 동작을 하며, 새로운 버전을 생성하여 과거 데이터를 유지함.

(3) DELETE (Dead Tuple 생성)

DELETE FROM user WHERE id = 1;
user(사용자) 테이블에서 식별자(id)에서 '1'인 row를 삭제.
 
 

✅ DELETE는 기존 튜플을 제거하는 것이 아니라, xmax를 업데이트하여 더 이상 조회되지 않도록 함.

id name xmin xmax
1 Alice Smith 1002 1003
  • 기존 튜플의 xmax = 1003으로 변경 (이제 이 튜플을 읽을 수 없음)
  • 하지만 실제로 디스크에서 삭제된 것은 아님 (VACUUM이 필요함)

 

3️⃣ MVCC와 트랜잭션 격리 수준

PostgreSQL은 MVCC를 기반으로 다양한 트랜잭션 격리 수준을 지원한다.

격리 수준 설명 읽기 일관성 Phantom Read 방지
Read Uncommitted 다른 트랜잭션의 미완료 변경 사항을 볼 수 있음
Read Committed (기본값) 커밋된 변경 사항만 볼 수 있음
Repeatable Read 트랜잭션 시작 시점의 데이터만 보임 (다른 트랜잭션이 변경한 내용 안 보임)
Serializable 가장 강력한 격리 수준 (트랜잭션을 직렬화하여 실행)

PostgreSQL 기본값은 READ COMMITTED이며, 성능과 일관성을 고려한 최적의 선택

REPEATABLE READ 이상을 사용하면 MVCC가 더욱 강력하게 동작하여 일관성을 보장

 

 

4️⃣ MVCC와 Vacuum

MVCC에서는 과거 버전의 튜플(Dead Tuple)이 계속 남아 있으므로, 주기적으로 정리해야 함.

  • Dead Tuple이 많아지면 성능 저하 발생
  • PostgreSQL은 이를 해결하기 위해 VACUUM 프로세스를 실행

Vacuum의 역할

  • Dead Tuple을 제거하여 디스크 공간을 확보
  • 트랜잭션 ID(XID) Wraparound 방지
  • Query Planner가 최신 통계를 사용할 수 있도록 갱신 (ANALYZE)

 

5️⃣ MVCC 성능 최적화 전략

Dead Tuple 모니터링 및 Vacuum 튜닝

  • autovacuum_vacuum_scale_factor = 0.05 (5% 변경 시 자동 Vacuum 실행)
  • autovacuum_naptime = 30s (더 자주 실행)

Fillfactor 조정

  • UPDATE가 많은 테이블은 fillfactor = 80으로 설정하여 HOT (Heap-Only Tuple) 최적화

인덱스 정리

  • UPDATE가 많은 테이블은 REINDEX TABLE을 주기적으로 실행하여 인덱스 크기 최적화

HOT (Heap-Only Tuple) 최적화

  • UPDATE가 인덱스 키를 변경하지 않으면 기존 페이지에서 데이터 수정 가능
  • 이를 위해 인덱스 컬럼을 변경하는 UPDATE를 줄이는 것이 성능 최적화의 핵심!

 

✅ 결론

🔹 PostgreSQL의 MVCC는 동시성 제어를 위한 핵심 기술로, 락 없이 여러 트랜잭션이 독립적으로 실행 가능
🔹 UPDATE 및 DELETE는 Dead Tuple을 생성하므로, 정기적인 VACUUM이 필수
🔹 트랜잭션 격리 수준에 따라 MVCC 동작 방식이 다름 (READ COMMITTED가 기본값)
🔹 autovacuum을 튜닝하여 Dead Tuple을 최소화하면 성능 최적화 가능

MVCC의 원리를 이해하고 튜닝하면 PostgreSQL의 성능을 극대화할 수 있음!

'PostgreSQL' 카테고리의 다른 글

PostgreSQL - VACUUM  (0) 2025.02.23
PostgreSQL - Tuple  (0) 2025.02.23
PostgreSQL - Memory - Shared Buffer  (0) 2025.02.22
PostgreSQL - Memory - Backend Buffer  (0) 2025.02.22
PostgreSQL - Idle Session' Memory  (0) 2025.02.22

+ Recent posts