※ PostgreSQL: MVCC.
※ Version: PostgreSQL 17.
안녕하세요. 듀스트림입니다.
아니.. 이걸 포스팅 안했더라고요?
그래서 작성하는 오늘의 포스팅은 PostgreSQL의 MVCC 관련 내용입니다.
1. PostgreSQL MVCC란?
PostgreSQL은 높은 동시성 처리를 위해 MVCC(Multi-Version Concurrency Control) 방식을 사용합니다.
MVCC에서는 트랜잭션이 데이터를 읽을 때 현재 데이터 상태를 직접 조회하는 것이 아니라 snapshot을 기준으로 튜플의 가시성(visibility)을 판단합니다.
이 방식 덕분에 한 트랜잭션이 데이터를 읽는 동안 다른 트랜잭션이 동일한 데이터를 수정하더라도 서로 블로킹 없이 동시에 작업할 수 있습니다.
중요한 점은 PostgreSQL의 MVCC는 단순히 현재 트랜잭션 ID 하나만으로 가시성을 판단하는 것이 아니라 snapshot을 기준으로 판단한다는 점입니다.
또한 snapshot의 유지 방식은 격리 수준(Isolation Level) 에 따라 달라집니다.
| Isolation Level | Snapshot 생성 시점 |
| Read Committed | 각 statement 시작 시 새로운 snapshot 생성 |
| Repeatable Read | 트랜잭션 시작 시 snapshot 생성 |
| Serializable | 트랜잭션 시작 시 snapshot 생성 |
따라서 같은 트랜잭션 내부에서도 Read Committed에서는 두 번의 SELECT 결과가 달라질 수 있습니다.
반면 Repeatable Read 이상에서는 트랜잭션 시작 시 생성된 snapshot을 계속 사용하기 때문에 동일한 SELECT 결과가 유지됩니다.
핵심 원리
PostgreSQL의 MVCC는 다음과 같은 방식으로 동작합니다.
- 각 statement 또는 transaction 시작 시 snapshot을 획득합니다.
- xmin : snapshot 기준에서 과거로 확실히 간주할 수 있는 트랜잭션 ID의 하한 경계
- xmax : 아직 시작되지 않은 트랜잭션 ID
- xip : snapshot 생성 시점에 실행 중인 트랜잭션 목록
- 데이터가 변경될 때 PostgreSQL은 기존 튜플을 직접 수정하지 않고 새로운 버전의 튜플을 생성합니다.
- 각 튜플에는 다음과 같은 메타 정보가 저장됩니다.
| 필드 | 의미 |
| xmin | 해당 튜플을 생성한 트랜잭션 ID |
| xmax | 해당 튜플을 삭제하거나 업데이트한 트랜잭션 ID |
쿼리는 이 xmin/xmax 값과 snapshot 정보를 비교하여 해당 튜플이 현재 트랜잭션에서 보이는지 여부를 판단합니다.
13.1. Introduction
13.1. Introduction # PostgreSQL provides a rich set of tools for developers to manage concurrent access to data. Internally, data consistency …
www.postgresql.org
2. 트랜잭션 ID(XID)의 부여와 증가 원리
PostgreSQL은 각 트랜잭션마다 고유한 32비트 정수형 Transaction ID(XID)를 부여합니다.
이 값은 전역적으로 증가하며, 다음에 할당될 XID는 pg_control에 저장된 nextXid 값을 기준으로 관리됩니다.
- PostgreSQL 13부터는 트랜잭션 ID를 조회하는 새로운 인터페이스로 pg_current_xact_id() 및 pg_current_xact_id_if_assigned() 함수가 도입되었습니다.
- pg_current_xact_id()는 현재 트랜잭션에 XID가 아직 할당되지 않았다면 새로운 XID를 할당하여 반환하며, pg_current_xact_id_if_assigned()는 트랜잭션에 이미 XID가 존재하는 경우에만 값을 반환하고 아직 할당되지 않았다면 NULL을 반환합니다.
- 기존 txid_current() 계열 함수도 여전히 사용 가능하지만, 이는 과거 인터페이스와의 호환성을 위해 유지되고 있습니다.
9.27. System Information Functions and Operators
9.27. System Information Functions and Operators # 9.27.1. Session Information Functions 9.27.2. Access Privilege Inquiry Functions 9.27.3. Schema Visibility Inquiry Functions …
www.postgresql.org
- XID의 최대값은 2³² − 1 (약 42억) 입니다.
- PostgreSQL은 트랜잭션 가시성을 판단할 때 현재 트랜잭션 기준 약 2³¹(약 21억) 범위의 과거 XID만을 유효한 것으로 간주합니다.
- 이 범위를 초과하면 XID가 wraparound 되어 데이터 가시성 오류가 발생할 수 있으므로, VACUUM을 통해 오래된 튜플의 XID를 Frozen 처리하여 관리합니다.
- 트랜잭션은 시작 시점에 즉시 XID를 할당받지 않으며, 실제로 데이터 변경(쓰기)이나 row-level lock이 필요한 시점에 XID가 지연 할당됩니다.
따라서 일반적인 읽기 전용 SELECT 트랜잭션은 XID를 소비하지 않지만, SELECT FOR UPDATE나 특정 함수 호출이 발생하면 XID가 할당될 수 있습니다.
PostgreSQL의 트랜잭션 ID는 단순한 카운터가 아니라 MVCC 가시성 판단의 핵심 기준으로 사용됩니다.
XID Wraparound의 문제
XID가 순환되면, 오래된 트랜잭션과 새로운 트랜잭션의 구분이 어려워져 데이터의 가시성 문제가 발생할 수 있습니다.
이러한 문제를 방지하기 위해 PostgreSQL은 다음과 같은 보호 장치를 가지고 있습니다.
- VACUUM [FREEZE]: VACUUM 작업을 통해 오래된 튜플의 xid를 FrozenTransactionId(Frozen Bit)로 설정하여 wraparound를 방지합니다.
- AUTOVACUUM: autovacuum_freeze_max_age 등의 설정을 통해 원하는 시점에 자동으로 VACUUM 작업이 수행되도록 구성할 수 있습니다.
XID Wraparound 기준 요약
| 항목 | 값 |
| XID 전체 범위 | 0 ~ 4,294,967,295 (2³² - 1) |
| wraparound 기준 | ±2,147,483,648 (2³¹) |
| 안전 비교 가능 범위 | 현재 XID 기준으로 앞뒤 약 21억까지 |
| 판단 방식 | (xmin - 현재XID) → signed 32비트 해석 |
signed 32bit?
- signed는 "부호 있는"을 의미합니다. 즉, 이 데이터는 양수와 음수를 모두 표현할 수 있습니다.
- 양수와 음수를 모두 표현하려면, 한 비트(최상위 비트)가 부호 비트로 사용됩니다.
- 그래서 양수와 음수를 표현할 수 있는 값의 범위가 반반 나뉩니다.
| 범위 | 값 |
| 최소값 | -2,147,483,648 (−2³¹) |
| 최대값 | 2,147,483,647 (2³¹ − 1) |
| 총 개수 | 4,294,967,296 (2³²) |
3. 튜플의 구조: xmin, xmax, t_infomask
PostgreSQL의 각 튜플(row)은 다음과 같은 메타데이터를 포함합니다.
| 필드 | 설명 |
| xmin | 이 튜플을 생성한 트랜잭션의 XID |
| xmax | 이 튜플을 삭제하거나 갱신한 트랜잭션의 XID |
| t_infomask | 각종 상태 비트 (힌트 비트, 락 상태, frozen 등) |
HeapTupleHeaderData 구조체 (C 코드)
typedef struct HeapTupleHeaderData {
...
TransactionId t_xmin; // 생성 트랜잭션
TransactionId t_xmax; // 삭제 트랜잭션
uint16 t_infomask; // 상태 플래그
...
} HeapTupleHeaderData;
※ 여기에 더해 ctid 시스템 컬럼을 함께 확인하면 MVCC 동작을 이해하는 데 도움이 됩니다.
ctid는 현재 튜플의 물리적 위치(TID)를 나타내는 시스템 컬럼으로 (block_number, tuple_offset) 형태의 값을 가집니다.
PostgreSQL에서 UPDATE가 수행되면 기존 튜플을 직접 수정하지 않고 새로운 튜플 버전을 생성합니다.
이때 기존 튜플의 tuple header에 있는 t_ctid 필드는 새로 생성된 튜플의 위치를 가리키게 되며, 이를 통해 version chain이 형성됩니다.
PostgreSQL은 이 version chain을 따라가며 최신 튜플을 확인할 수 있으며, 특히 HOT(Heap Only Tuple) 업데이트가 발생한 경우 동일한 heap page 내부에서 이 체인이 연결됩니다.
ctid는 현재 튜플의 물리적 위치를 나타내므로 물리적 위치 확인이나 디버깅 목적으로는 유용합니다.
다만 UPDATE, VACUUM FULL, CLUSTER 등의 작업이 수행되면 튜플의 물리적 위치가 변경될 수 있으므로 논리적인 row의 영구 식별자로 사용하는 것은 적절하지 않습니다.
4. 트랜잭션 가시성(Visibility) 판단 방식
PostgreSQL의 가시성 판단은 단순히 xmin < 현재 XID 와 같은 단일 비교로 결정되지 않습니다.
실제로는 현재 statement 또는 transaction이 보유한 snapshot 정보, tuple의 xmin / xmax, 그리고 해당 트랜잭션의 commit / abort 상태(pg_xact) 를 함께 사용하여 tuple의 visible 여부를 판단합니다.
PostgreSQL snapshot은 다음과 같은 정보를 포함합니다.
| 필드 | 의미 |
| xmin | snapshot 기준에서 확실히 과거로 간주할 수 있는 트랜잭션 ID의 하한 경계 |
| xmax | snapshot 시점에서 아직 시작되지 않은 트랜잭션 ID의 경계 |
| xip | snapshot 생성 시점에 실행 중이던 트랜잭션 ID 목록 |
위 설명은 MVCC의 핵심 개념을 이해하기 위한 단순화된 snapshot 구조이며, 실제 PostgreSQL 내부에서는 snapshot 종류와 트랜잭션 상태 등을 함께 고려합니다.
MVCC visibility 판단의 핵심은 단순히 현재 XID보다 작은지 여부가 아니라, 해당 tuple을 생성하거나 삭제한 트랜잭션이 현재 snapshot 기준에서 visible 상태인지를 판단하는 것입니다.
튜플 가시성 판단 조건
튜플이 visible하기 위해서는 대략 다음과 같은 조건을 만족해야 합니다.
| 순서 | 조건 | 의미 |
| 1 | xmin < snapshot xmax | 미래 트랜잭션이 아님 |
| 2 | xmin ∉ snapshot xip | 진행 중 트랜잭션이 아님 |
| 3 | xmin committed | 생성 트랜잭션이 정상 커밋됨 |
| 4 | xmax = InvalidTransactionId | 삭제되지 않음 |
| 5 | 또는 xmax 트랜잭션이 아직 커밋되지 않음 | 삭제가 확정되지 않음 |
위 조건은 MVCC visibility의 핵심 원리를 설명하기 위한 단순화된 흐름이며, 실제 PostgreSQL 내부에서는 tuple header 상태 비트(t_infomask), snapshot 종류, command id, 현재 트랜잭션 자신 여부 등을 함께 고려합니다.
가시성 판단 흐름
PostgreSQL executor는 대략 다음 순서로 튜플을 검사합니다.
- xmin이 snapshot 기준 미래 트랜잭션인지 확인
- xmin 트랜잭션의 commit 상태 확인
- xmax 존재 여부 확인
- xmax 트랜잭션의 commit 상태 확인
이 과정은 PostgreSQL 내부 함수인 HeapTupleSatisfiesVisibility()에서 수행됩니다.
실제 PostgreSQL 내부에서는 tuple header의 상태 비트(t_infomask), snapshot 종류, 현재 트랜잭션 자신이 수행한 변경인지 여부, 커맨드 ID(Command ID) 등의 요소까지 함께 고려하여 더 복잡하게 가시성을 판단합니다.
다만 실무적으로는 xmin/xmax + snapshot + commit status 조합으로 이해하면 MVCC의 핵심 원리를 파악하는 데 충분합니다.
XID 비교 방식
PostgreSQL은 XID wraparound 문제를 처리하기 위해 단순한 정수 비교 대신 다음 방식으로 XID 순서를 판단합니다.
TransactionIdPrecedes(xid1, xid2) ⇨ ((int32)(xid1 - xid2)) < 0
- 이 방식은 32비트 XID가 wraparound 되더라도 올바른 시간 순서를 판단할 수 있도록 설계되었습니다.
- 예를 들어 (xid1 - xid2) 값을 signed 32bit 정수로 해석했을 때 음수이면 xid1이 더 과거 트랜잭션으로 판단됩니다.
XID 가시성 판단 예제
| 현재 XID | 튜플의 xmin | 계산 결과(signed) | Visibility | 설명 |
| 11 | 100 | +89 | ✅ | 정상 과거 |
| 11 | 2³¹ - 1 | +2,147,483,636 | ❌ | wraparound 범위 초과 |
| 11 | 2³² - 6 | -17 | ✅ | wraparound 발생 후지만 과거 |
| 100 | 90 | -10 | ✅ | 정상 과거 |
| 100 | 2³¹ | +2,147,483,548 | ❌ | wraparound 기준 초과 |
| 100 | 4,294,967,295 | -101 | ✅ | wraparound 직전 ID, 과거로 간주 |
| UPDATE = DELETE + INSERT | |
| old tuple | xmin = 100 xmax = 105 |
| new tuple | xmin = 105 xmax = 0 |
논리적으로는 DELETE + INSERT처럼 동작합니다.
※ PostgreSQL의 UPDATE는 기존 row를 제자리에서 직접 수정하는 방식이 아닙니다.
기존 튜플을 바로 덮어쓰지 않고, 새로운 row version을 새로 생성하는 방식으로 동작합니다.
이 과정에서 기존 버전의 튜플에는 xmax 정보가 남고, 새로 생성된 버전의 튜플에는 xmin 정보가 기록됩니다.
즉 하나의 논리적인 row가 물리적으로는 여러 버전의 tuple로 존재할 수 있으며, 이 구조를 기반으로 PostgreSQL은 읽기와 쓰기가 서로 블로킹되지 않는 높은 동시성을 제공합니다.
5. 힌트 비트 (Hint Bit)
힌트 비트는 t_infomask에 기록되며, 트랜잭션의 상태가 pg_xact 파일을 매번 조회하지 않도록 캐시된 정보입니다.
| 비트 플래그 | 의미 |
| HEAP_XMIN_COMMITTED | xmin 트랜잭션이 커밋됨 |
| HEAP_XMIN_INVALID | xmin 트랜잭션이 실패(abort)함 |
| HEAP_XMAX_COMMITTED | xmax 트랜잭션이 커밋됨 (즉, 이 튜플은 삭제됨) |
| HEAP_XMAX_INVALID | xmax 트랜잭션이 실패함 |
| HEAP_XMIN_FROZEN | xmin이 FrozenTransactionId로 취급됨 (21억 초과 대비) |
힌트 비트가 필요한 이유
각 트랜잭션이 튜플을 읽을 때마다 pg_xact에서 트랜잭션 상태(커밋/롤백 여부)를 확인하면 I/O 부담이 큽니다.
그래서 PostgreSQL은 힌트 비트(Hint Bit)를 사용해 "이 트랜잭션은 이미 커밋됐다"는 사실을 튜플 헤더에 표시해둡니다.
→ 다음번 SELECT에서는 pg_xact 확인 없이 빠르게 처리 가능해집니다.
힌트 비트의 특징
- 트랜잭션이 해당 튜플을 읽는 순간 비트를 설정함 (SELECT 등)
- WAL에는 기본적으로 기록되지 않음 → 장애 시 손실 가능
- wal_log_hints = on 이면 hint bit 변경도 WAL 보호 대상이 됩니다.
6. MVCC와 복제, WAL, 힌트 비트의 상호작용
Hot Standby 기반의 Streaming Replication 환경에서는 힌트 비트(Hint Bit)와 WAL 기록 방식이 서로 영향을 미칩니다.
힌트 비트는 튜플의 가시성 판단을 빠르게 하기 위한 페이지 내부 메타데이터이며, 일반적인 데이터 변경과 달리 항상 WAL에 기록되는 것은 아닙니다.
따라서 복제 환경에서는 다음과 같은 특성을 이해해야 합니다.
wal_log_hints
이 설정을 활성화하면 힌트 비트 변경도 WAL에 기록됩니다.
주요 목적은 다음과 같습니다.
- 힌트 비트 변경을 WAL로 보호
- data checksums 미사용 환경에서도 페이지 변경을 WAL에 기록
- pg_rewind 사용을 위한 필수 조건
PostgreSQL 공식 문서에서도 pg_rewind 사용을 위해서는 다음 중 하나가 필요하다고 설명합니다.
- data checksums enabled
- wal_log_hints = on
Streaming Replication에서 힌트 비트 동작
Streaming Replication에서는 다음과 같은 특징이 있습니다.
- 힌트 비트는 반드시 WAL로 전파되는 정보가 아닙니다.
- 따라서 Primary에서 설정된 힌트 비트가 Standby로 반드시 전달되는 것은 아닙니다.
- Standby에서도 쿼리 실행 중 페이지를 읽으면서 힌트 비트를 독립적으로 설정할 수 있습니다.
즉, Primary와 Standby의 힌트 비트 상태는 서로 다를 수 있습니다.
하지만 이는 데이터 일관성에는 영향을 주지 않습니다.
힌트 비트는 MVCC 가시성 판단을 빠르게 하기 위한 캐시 정보일 뿐이며, 실제 트랜잭션 가시성은 항상 WAL과 clog(pg_xact)을 기준으로 판단합니다.
Hint Bit와 Full Page Write
힌트 비트는 WAL에 기록되지 않는 경우가 많지만 다음 상황에서는 WAL 기록이 발생할 수 있습니다.
- wal_log_hints = on
- data checksums enabled
이 경우 페이지의 힌트 비트 변경도 WAL 보호 대상이 됩니다.
특히 다음 상황에서 WAL 증가가 발생할 수 있습니다.
- checkpoint 이후
- 페이지가 처음 수정되는 경우
- full_page_writes = on 상태
이 경우 PostgreSQL은 Full Page Image(FPI)를 WAL에 기록합니다.
checkpoint 이후 → 페이지 최초 수정 + 힌트 비트 변경 + wal_log_hints 또는 checksum → Full Page Write 발생 가능
이로 인해 읽기 중심 워크로드에서도 WAL이 증가할 수 있습니다.
정리
| 항목 | 설명 |
| 힌트 비트 | MVCC 가시성 판단 최적화용 메타데이터 |
| WAL 기록 여부 | 기본적으로 기록되지 않음 |
| WAL 기록 조건 | wal_log_hints=on 또는 data checksums |
| Streaming Replication | 힌트 비트는 Primary와 Standby가 다를 수 있음 |
| 데이터 일관성 | 영향 없음 |
| WAL 증가 가능성 | checkpoint 이후 hint bit 변경 시 FPI 발생 가능 |
힌트 비트는 데이터 변경이 아니라 MVCC 가시성 캐시 정보입니다.
따라서 Primary와 Standby 간에 동일할 필요는 없으며, 필요할 경우 각 노드에서 독립적으로 설정됩니다.
다만 wal_log_hints 또는 data checksums가 활성화된 경우에는 힌트 비트 변경도 WAL 보호 대상이 되기 때문에 WAL 양 증가에 영향을 줄 수 있습니다.
7. 프로즌 비트 (Frozen Bit)
PostgreSQL의 트랜잭션 ID는 32비트로 약 42억(2³²) 범위를 갖습니다.
하지만 MVCC 가시성 판단 특성상 현재 트랜잭션 기준 약 2³¹(약 21억) 범위를 초과하면 wraparound 문제가 발생할 수 있습니다.
이를 방지하기 위해 PostgreSQL은 오래된 튜플을 Frozen 상태로 표시하여 해당 xmin을 항상 visible한 트랜잭션으로 간주하도록 처리합니다.
동작 방식
- VACUUM FREEZE 또는 autovacuum이 오래된 튜플을 탐색합니다.
- 충분히 오래된 튜플은 freeze 처리가 수행됩니다.
- 최신 PostgreSQL에서는 freeze 상태가 주로 tuple hint bit (HEAP_XMIN_FROZEN) 로 표현됩니다.
과거 PostgreSQL 버전에서는 freeze 처리 시 xmin 값을 FrozenTransactionId (2) 로 직접 변경하는 방식이 사용되었습니다.
현재 버전에서도 특정 상황에서는 여전히 xmin = 2 형태가 나타날 수 있으며, 특히 pg_upgrade 이후 오래된 클러스터에서는 이러한 튜플이 남아 있을 수 있습니다.
관련 설정값
| 파라미터 | 설명 |
| vacuum_freeze_min_age | 튜플 freeze 가능 최소 age |
| vacuum_freeze_table_age | aggressive freeze 시작 기준 |
| autovacuum_freeze_max_age | wraparound 방지 강제 vacuum |
| vacuum_multixact_freeze_min_age | multixact freeze 기준 |
PostgreSQL의 freeze는 단순한 xmin 변경이 아니라, 해당 튜플의 트랜잭션 가시성 검사를 생략하기 위한 최적화이기도 합니다.
8. pg_xact: 트랜잭션 상태 저장소
pg_xact 디렉토리는 각 트랜잭션 ID의 상태(COMMITTED, ABORTED 등)를 2비트 단위로 저장하는 Transaction Commit Log 입니다.
PostgreSQL은 튜플의 가시성을 판단할 때 힌트 비트가 설정되어 있지 않다면 pg_xact 정보를 조회하여 트랜잭션 상태를 확인합니다.
pg_xact는 SLRU(Simple LRU) 캐시를 통해 관리되며, 캐시에 존재하지 않는 경우에만 디스크에서 해당 페이지를 읽게 됩니다.
따라서 힌트 비트가 설정되면 pg_xact 조회를 생략할 수 있어 가시성 체크 비용이 크게 감소합니다.
즉 힌트 비트는 MVCC에서 반복적인 pg_xact 조회를 줄여 성능을 개선하는 중요한 최적화 메커니즘입니다.
pg_xact 조회 흐름
pg_xact는 SLRU(Simple LRU) 캐시를 통해 관리되며, 캐시에 없는 경우에만 디스크에서 읽게 됩니다.
tuple visibility check
↓
hint bit 존재?
↓
없으면
↓
TransactionIdDidCommit()
↓
pg_xact SLRU cache 확인
↓
cache miss 시 디스크 read
힌트 비트가 설정되어 있다면 pg_xact 조회를 줄일 수 있습니다.
tuple visibility check
↓
hint bit 확인
↓
pg_xact lookup 생략
요약 표
| 항목 | 의미 |
| pg_xact | 트랜잭션 상태 저장 |
| 저장 방식 | 2bit per transaction |
| 접근 방식 | SLRU cache |
| hint bit 역할 | pg_xact lookup 제거 |
| 효과 | visibility check 비용 감소 |
여기서 한 가지 헷갈리기 쉬운 부분이 있습니다.
Hint Bit와 Visibility Map은 역할이 서로 다릅니다.
- Hint Bit: 개별 tuple 수준에서 xmin/xmax의 커밋 여부를 빠르게 판단하기 위한 캐시
- Visibility Map: 페이지 단위로 "이 페이지의 모든 튜플이 전체적으로 visible한가", "all-frozen인가"를 기록하는 정보
Hint Bit는 tuple 단위 최적화이고, Visibility Map은 page 단위 최적화입니다.
둘 다 visibility와 관련은 있지만, 저장 단위와 사용 목적이 다르다는 점을 구분해서 보면 이해가 훨씬 쉬워집니다.
9. FSM(Free Space Map) & Visibility Map
VACUUM에 등장할 내용이지만 이해를 돕기 위해 간략하게 작성합니다.
FSM (Free Space Map)
- FSM은 테이블 블록마다 남은 여유 공간을 추적합니다.
- PostgreSQL은 INSERT 시 새로운 페이지를 할당하기 전 FSM을 참고하여 빈 공간이 있는 페이지를 재사용합니다.
- FSM은 VACUUM이 정리된 페이지의 여유 공간을 반영하여 업데이트합니다.
Visibility Map (VM)
- VM은 각 페이지가 모든 튜플이 visible한지(all-visible)와 freeze 상태인지(all-frozen)를 각각 기록합니다.
- Visibility Map은 heap page마다 2개의 비트를 가집니다.
- all-visible
- all-frozen
- all-visible
- Visibility Map은 heap page마다 2개의 비트를 가집니다.
- VACUUM은 VM을 참고하여 이미 모두 frozen된 페이지는 건너뜁니다.
- Index Only Scan은 VM을 통해 heap 접근 없이 인덱스만으로 결과를 반환할 수 있는지를 판단합니다.
10. 팁
- 힌트 비트로 인해 SELECT만 수행해도 디스크 write가 발생할 수 있음 → Write spike 주의
- ORDER BY로 인한 테이블 풀스캔 + 힌트 비트 update로 예상치 못한 IOPS 증가 가능
- 힌트 비트를 미리 설정하려면 자주 사용하는 테이블에 대해 VACUUM 주기적으로 실행
- Index Only Scan 가능 여부는 Visibility Map의 all-visible 비트를 기준으로 판단됩니다.
- 힌트 비트는 tuple 단위 visibility 판단을 빠르게 만드는 역할을 하며, Visibility Map은 페이지 단위 최적화를 담당합니다.
다음 주제는 자연스럽게 VACUUM으로 하겠습니다.
오늘은 여기까지~
'PostgreSQL' 카테고리의 다른 글
| PostgreSQL: TOAST (0) | 2025.05.21 |
|---|---|
| PostgreSQL: VACUUM (0) | 2025.05.17 |
| PostgreSQL: SLRU(Simple Least Recently Used) 버퍼 캐시 (0) | 2025.05.15 |
| PostgreSQL: Latency Spike 관련 (0) | 2025.05.14 |
| PostgreSQL vs Oracle: 실행 계획 캐싱 전략과 통계 수집의 민감도 비교 분석 (0) | 2025.05.12 |