DB Study

13장. Extension 생태계 — 같은 엔진, 무한한 변신

PostgreSQL의 진짜 강점은 엔진이 아니라 생태계입니다. 같은 바이너리가 extension에 따라 시계열 DB도, 벡터 검색 엔진도, 지리정보 시스템도 됩니다 — 플러그인이 아니라 "코어에 직접 연결되는 일급 시민"이기 때문입니다.

중급 ⏱ 약 25분 🎬 애니메이션 2개 선수 지식: 2장 아키텍처
🧭
이 장에서 배우는 것

① Extension이 훅(Hook)으로 코어에 연결되는 구조 ② shared_preload_libraries와 CREATE EXTENSION의 차이 ③ 반드시 켜야 할 pg_stat_statements 활성화 흐름 ④ 목적별 대표 extension 지도

13.1 Extension은 어떻게 코어에 "끼어드는가"

PostgreSQL 코어에는 쿼리 처리 경로 곳곳에 훅(Hook)이라는 함수 포인터가 심어져 있습니다. 평소에는 비어 있지만, extension이 자기 함수를 등록하면 모든 쿼리가 그 함수를 통과하게 됩니다. 콘센트(훅)에 플러그(extension)를 꽂는 셈이죠. 이 밖에도 SPI(내부 SQL 실행), FDW(외부 데이터 소스), Index AM(새 인덱스 타입 — pgvector의 HNSW가 이것) 같은 공식 API가 열려 있습니다.

PostgreSQL 코어 Parser Planner Executor planner_hook ExecutorEnd_hook ← 훅 = 비어 있는 함수 포인터 (콘센트 🔌) pg_stat_statements.so 서버 시작 시 preload → 훅에 함수 등록 쿼리 실행 실행이 끝날 때마다 extension 함수가 호출됨 실행 시간·호출 횟수를 공유 메모리에 누적 SELECT * FROM pg_stat_statements 누적 통계를 SQL 뷰로 조회 코어 소스는 한 줄도 안 고쳤다 — 이것이 "일급 시민" 확장의 의미

13.2 두 개의 스위치 — preload와 CREATE EXTENSION

Extension 활성화에는 종류에 따라 두 단계의 스위치가 있습니다. 이걸 혼동하면 "설치했는데 왜 안 되지?"의 늪에 빠집니다.

스위치시점하는 일대상
shared_preload_libraries서버 시작 시 (재시작 필요).so를 프로세스에 로드, 훅 등록, 공유 메모리 확보pg_stat_statements, auto_explain, pgaudit, pg_cron 등
CREATE EXTENSION언제든 (DB 단위)SQL 객체(뷰·함수·타입·연산자) 생성모든 extension — 단 DB마다 따로 실행
# ① postgresql.conf — 프로세스 레벨 (재시작 필요)
shared_preload_libraries = 'pg_stat_statements,auto_explain'
pg_stat_statements.max = 10000
pg_stat_statements.track = all

-- ② 재시작 후, 사용할 DB에서 — SQL 객체 생성
CREATE EXTENSION pg_stat_statements;

-- 확인: 설치 가능/설치된 extension
SELECT name, default_version, installed_version
FROM pg_available_extensions ORDER BY name;
postgresql.conf shared_preload_ libraries = '...' 🔄 서버 재시작 .so 로드 + 훅 등록 CREATE EXTENSION 뷰·함수 생성 (DB마다!) 📊 조회 누적 통계 postgresql.conf shared_preload_ libraries = '...' 🔄 서버 재시작 .so 로드 + 훅 등록 CREATE EXTENSION 뷰·함수 생성 (DB마다!) SELECT query, calls, mean_exec_time FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 20; → "우리 DB에서 제일 무거운 쿼리 TOP 20"이 한 방에
⚠️
"CREATE EXTENSION 했는데 안 돼요"의 90%

preload가 필요한 extension(pg_stat_statements, auto_explain, pgaudit, pg_cron)을 shared_preload_libraries에 넣지 않았거나 재시작을 빠뜨린 경우입니다. 반대로 pg_trgm, postgis, pgvector 등은 preload 없이 CREATE EXTENSION만으로 동작합니다.

13.3 대표 Extension 지도 — 목적별 카드

📊 pg_stat_statements

쿼리를 정규화해 실행 횟수·시간·버퍼 히트를 누적. 운영 환경 1순위 설치. preload 필요.

🔍 auto_explain

임계값(예: 1초) 이상 걸린 쿼리의 실행 계획을 로그에 자동 기록. 재현 안 되는 장애의 결정적 증거. preload 필요.

🛡️ pgaudit

누가 언제 어떤 SQL을 실행했는지 감사 로그. 금융·공공·의료 규제 대응 필수. preload 필요.

🔤 pg_trgm

LIKE '%foo%'와 오타 허용 검색을 GIN 인덱스로 가속. similarity() 유사도 계산.

🌍 PostGIS

지리정보 표준. 좌표계 변환, 공간 조인, 반경 검색(ST_DWithin), KNN까지.

🧠 pgvector

LLM 임베딩 유사도 검색. v0.5+의 HNSW 인덱스로 실전 수준 속도. <=> 코사인 거리 연산자.

⏰ pg_cron

DB 안에서 cron 문법으로 SQL 스케줄링. 파티션 생성·VACUUM 등 유지보수 자동화. preload 필요.

📅 pg_partman

12장의 파티션 생성/삭제 로테이션을 자동화. pg_cron과 짝으로 쓰는 것이 표준.

📈 TimescaleDB

시계열 특화 — hypertable 자동 파티셔닝, 압축, 연속 집계. 라이선스(Apache 2.0/TSL) 확인 필수.

🌐 Citus

테이블을 여러 워커 노드로 분산(샤딩)해 스케일 아웃. 멀티테넌트 SaaS에 적합.

🚪 pgBouncer

(extension은 아니지만) 커넥션 풀링의 사실상 표준. transaction 모드가 일반적 선택. 14장 참조.

🔧 pg_repack

VACUUM FULL 없이 무중단으로 테이블 재구성 — Bloat 제거의 운영 표준. 8장 참조.

실무에서 자주 쓰는 조합을 외워두면 아키텍처 결정이 빨라집니다.

목적추천 조합
기본 모니터링pg_stat_statements + auto_explain
대량 데이터 관리pg_partman + pg_cron
전문/유사 검색pg_trgm + btree_gin
AI/임베딩pgvector + pg_trgm (하이브리드 검색)
규제 대응pgaudit + pgcrypto

13.4 손으로 익히기 — pg_trgm과 pgvector 맛보기

-- pg_trgm: LIKE '%…%'를 인덱스 스캔으로
CREATE EXTENSION pg_trgm;
CREATE INDEX ON users USING GIN (email gin_trgm_ops);

SELECT similarity('postgres', 'postgrez');   -- 0.625 (오타 유사도)
SELECT * FROM users WHERE email LIKE '%@danble.co%';  -- 이제 인덱스 사용!

-- pgvector: 임베딩 유사도 top-5
CREATE EXTENSION vector;
CREATE TABLE docs (id bigserial, content text, embedding vector(1536));
CREATE INDEX ON docs USING HNSW (embedding vector_cosine_ops);

SELECT id, 1 - (embedding <=> :q) AS similarity
FROM docs ORDER BY embedding <=> :q LIMIT 5;
💡
메이저 업그레이드 전 체크

pg_upgrade로 PostgreSQL을 올릴 때는 source에 설치된 모든 extension의 동일 버전이 target에도 준비되어 있어야 합니다. PostGIS·TimescaleDB는 자체 업그레이드 절차가 복잡하니 반드시 해당 프로젝트 가이드를 따르세요. shared_preload_libraries도 새 서버 conf에 별도로 옮겨야 합니다.

✍️ 이해도 체크

CREATE EXTENSION pg_stat_statements;를 실행했는데 뷰에 통계가 쌓이지 않습니다. 가장 유력한 원인은?
✅ pg_stat_statements는 훅 등록과 공유 메모리 확보를 위해 서버 시작 시 preload되어야 합니다. CREATE EXTENSION은 조회용 SQL 객체만 만들 뿐이라, preload 없이는 수집 자체가 일어나지 않습니다. "conf 등록 → 재시작 → CREATE EXTENSION" 순서를 기억하세요.
Extension이 PostgreSQL 코어의 동작을 바꿀 수 있는 이유로 가장 정확한 설명은?
✅ PostgreSQL은 planner_hook, ExecutorEnd_hook 같은 훅과 SPI·FDW·Index AM 등의 확장 API를 설계 차원에서 제공합니다. extension은 이 지점에 코드를 등록해 코어 수정 없이 동작을 확장합니다. pgvector가 HNSW라는 새 인덱스 타입을 추가할 수 있는 것도 Index AM API 덕분입니다.
📚
원문으로 더 깊이

이 장의 원문 문서: chapters/ch13_extensions.md — pgaudit 상세 설정, PostGIS geography vs geometry, pgvector 인덱스 파라미터, Citus 분산 테이블, pgBouncer 모드별 함정이 담겨 있습니다.