Series / PostgreSQL
GitHub

PostgreSQL 시리즈

내부 구조부터 실전 DBA까지, 쿼리가 느린 이유를 원리로 설명. 14편을 읽는 순서대로 정리했습니다.

Database2026.04.11.

PostgreSQL 아키텍처 한눈에 보기

PostgreSQL이 왜 프로세스 덩어리로 돌아가는지, 쿼리 한 줄이 postmaster → backend → shared memory → executor를 어떻게 지나가는지 따라가며 시리즈 14편의 지도를 그립니다.

PostgreSQL
PostgreSQL 아키텍처 한눈에 보기
Database2026.04.12.

PostgreSQL 힙 페이지와 튜플 구조: 데이터를 디스크에 어떻게 올려두는가

ctid는 PostgreSQL의 모든 row에 숨어 있는 시스템 컬럼으로, (페이지 번호, 슬롯 번호) 형태로 row가 디스크 어디에 있는지 가리키는 좌표입니다. UPDATE에 따라 ctid가 바뀌는 이유를 따라 8KB 페이지 구조, 튜플 헤더 23바이트, HOT update와 FILLFACTOR, TOAST까지 페이지 안쪽을 들여다봅니다.

PostgreSQL
PostgreSQL 힙 페이지와 튜플 구조: 데이터를 디스크에 어떻게 올려두는가
Database2026.04.13.

PostgreSQL MVCC와 튜플 가시성

두 트랜잭션이 같은 row를 읽었을 때 왜 다른 값이 보이는지, xmin/xmax와 snapshot의 조합으로 가시성이 어떻게 결정되는지, 그리고 xid가 42억을 넘기면 무슨 일이 일어나는지 손으로 풀어봅니다.

PostgreSQL
PostgreSQL MVCC와 튜플 가시성
Database2026.04.16.

PostgreSQL B-tree 인덱스 뜯어보기

B-tree 페이지가 디스크 위에 어떻게 놓여 있는지, 루트에서 리프까지 한 건을 찾아가는 경로, composite index의 선두 컬럼 규칙이 생기는 이유, 그리고 Index-Only Scan이 Visibility Map에 의존하는 이유를 실제 페이지를 뜯어보며 따라갑니다.

PostgreSQL
PostgreSQL B-tree 인덱스 뜯어보기
Database2026.04.18.

B-tree 너머: GIN, GiST, BRIN, Hash는 언제 쓰는가

전문 검색, JSONB 포함 관계, 시계열 거대 테이블처럼 B-tree가 다루지 못하는 영역이 있습니다. GIN·GiST·BRIN·Hash의 내부 구조가 각각 어떤 접근 패턴에 최적화돼 있는지, 언제 쓰고 언제 쓰면 안 되는지를 짚어봅니다.

PostgreSQL
B-tree 너머: GIN, GiST, BRIN, Hash는 언제 쓰는가
Database2026.04.19.

플래너 통계와 EXPLAIN 읽는 법

같은 쿼리가 어제는 Index Scan, 오늘은 Seq Scan이 되는 이유는 대부분 통계에 있습니다. 플래너가 pg_statistic의 숫자로 cost를 만드는 과정과 EXPLAIN 출력을 한 줄씩 해석하는 법, 추정치가 크게 틀어졌을 때 진단하는 법을 정리합니다.

PostgreSQL
플래너 통계와 EXPLAIN 읽는 법
Database2026.04.21.

PostgreSQL 조인 알고리즘: Nested Loop, Hash Join, Merge Join

같은 JOIN 쿼리가 왜 어떤 날은 Nested Loop, 어떤 날은 Hash Join이 되는지, work_mem이 Hash Join의 성능을 좌우하는 이유, 그리고 플래너가 조인 순서를 결정하는 원리를 세 알고리즘의 cost 공식과 함께 따라갑니다.

PostgreSQL
PostgreSQL 조인 알고리즘: Nested Loop, Hash Join, Merge Join
Database2026.04.22.

PostgreSQL 병렬 쿼리와 파티셔닝

대용량 테이블을 나눠 처리하는 두 가지 방식, 병렬 쿼리와 파티셔닝을 비교합니다. 병렬이 언제 켜지고 왜 안 켜지는지, 파티션 pruning이 걸리는 조건과 자주 놓치는 함정, 그리고 두 메커니즘이 만났을 때 어떤 효과가 나는지 짚어봅니다.

PostgreSQL
PostgreSQL 병렬 쿼리와 파티셔닝
Database2026.04.25.

VACUUM과 bloat의 정체: dead tuple은 누가 언제 치우는가

dead tuple은 UPDATE나 DELETE 뒤에도 페이지에 남아 있지만 더 이상 어떤 트랜잭션도 볼 필요가 없는 옛 버전의 튜플입니다. dead tuple이 만드는 bloat가 성능에 미치는 영향, VACUUM의 3단계 동작, autovacuum의 트리거 공식, wraparound를 막는 freeze까지 따라갑니다.

PostgreSQL
VACUUM과 bloat의 정체: dead tuple은 누가 언제 치우는가
Database2026.04.28.

트랜잭션 격리 수준과 락: 쓰기 충돌은 어떻게 해결되는가

두 트랜잭션이 같은 row를 동시에 UPDATE하면 어떤 일이 일어나는지, row-level lock이 튜플 헤더에 어떻게 기록되는지, 테이블 레벨 락 8단계, SSI가 write skew를 잡는 원리, 그리고 pg_locks로 블로킹을 진단하는 법까지 따라갑니다.

PostgreSQL
트랜잭션 격리 수준과 락: 쓰기 충돌은 어떻게 해결되는가
Database2026.04.30.

WAL과 체크포인트: crash에서 살아남는 구조, 그리고 성능의 숨은 비용

COMMIT 직후 전원이 꺼져도 데이터가 사라지지 않는 이유, WAL record와 LSN의 구조, Full Page Write가 WAL 볼륨을 키우는 원리, checkpoint가 I/O spike를 만드는 메커니즘, 그리고 crash recovery가 redo를 적용하는 과정까지 따라갑니다.

PostgreSQL
WAL과 체크포인트: crash에서 살아남는 구조, 그리고 성능의 숨은 비용
Database2026.05.03.

Streaming Replication과 Logical Replication: WAL을 네트워크로 보내는 두 가지 방법

WAL 바이트를 그대로 보내는 Streaming Replication과 row 단위로 디코딩하는 Logical Replication의 아키텍처, replication slot의 역할, hot standby 쿼리 충돌이 생기는 이유, 그리고 lag 측정과 failover까지 따라갑니다.

PostgreSQL
Streaming Replication과 Logical Replication: WAL을 네트워크로 보내는 두 가지 방법
Database2026.05.05.

느린 쿼리를 추적하는 법: pg_stat_statements부터 wait_event까지

"DB가 느려요"라는 모호한 증상에서 출발해, pg_stat_statements로 전체 워크로드의 병목을 찾고, auto_explain으로 실행 계획을 자동 수집하고, pg_stat_activity의 wait_event로 지금 무엇에 막혀 있는지 진단하는 체계를 만듭니다.

PostgreSQL
��느린 쿼리를 추적하는 법: pg_stat_statements부터 wait_event까지
Database2026.05.08.

연결, 메모리, autovacuum: 운영 환경에서 가장 자주 튜닝하는 파라미터들

PostgreSQL 운영에서 가장 자주 건드리는 세 축인 연결 관리(max_connections, PgBouncer), 메모리 파라미터(shared_buffers, work_mem, effective_cache_size), autovacuum 튜닝의 의미와 관계를 정리하고, 실전 장애 시나리오 3가지로 접목합니다.

PostgreSQL
연결, 메모리, autovacuum: 운영 환경에서 가장 자주 튜닝하는 파라미터들
Thank You for Visiting My Blog, Have a Good Day 😆