/엔지니어/데이터베이스/PostgreSQL 인덱스 최적화 — 느린 쿼리 진
데이터베이스고급UbuntuDebianCentOSPostgreSQL인덱스쿼리최적화

PostgreSQL 인덱스 최적화 — 느린 쿼리 진단과 인덱스 전략

EXPLAIN ANALYZE로 느린 쿼리를 찾고, 적절한 인덱스 타입을 선택하여 성능을 개선하는 방법을 실무 중심으로 정리합니다.

느린 쿼리 찾기

SQL
-- pg_stat_statements 활성화 (postgresql.conf)
shared_preload_libraries = 'pg_stat_statements'

-- 설치
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;

-- 상위 10개 느린 쿼리
SELECT
  round(total_exec_time::numeric, 2) AS total_ms,
  calls,
  round(mean_exec_time::numeric, 2) AS avg_ms,
  left(query, 100) AS query_preview
FROM pg_stat_statements
ORDER BY mean_exec_time DESC
LIMIT 10;

EXPLAIN ANALYZE 읽기

SQL
EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)
SELECT * FROM orders
WHERE user_id = 123 AND status = 'pending'
ORDER BY created_at DESC
LIMIT 10;

핵심 항목:

항목의미
Seq Scan전체 테이블 스캔 (인덱스 없음)
Index Scan인덱스 사용
Bitmap Heap Scan여러 인덱스 조합
actual time=0.1..5.2실제 실행 시간 (ms)
Buffers: shared hit=8캐시 히트 (miss가 많으면 I/O 문제)

인덱스 생성

SQL
-- 단일 컬럼
CREATE INDEX idx_orders_user_id ON orders (user_id);

-- 복합 인덱스 (선택성 높은 것 먼저)
CREATE INDEX idx_orders_user_status ON orders (user_id, status);

-- 부분 인덱스 (조건에 맞는 행만 인덱싱)
CREATE INDEX idx_orders_pending ON orders (created_at)
WHERE status = 'pending';

-- 표현식 인덱스
CREATE INDEX idx_users_email_lower ON users (lower(email));

-- 온라인 생성 (잠금 없이)
CREATE INDEX CONCURRENTLY idx_posts_category ON posts (category);

인덱스 타입 선택

SQL
-- B-tree: 기본, 범위 쿼리 (=, <, >, BETWEEN, LIKE 'prefix%')
CREATE INDEX idx_b ON events (created_at);

-- Hash: = 조건만, 빠름
CREATE INDEX idx_h ON sessions USING HASH (session_token);

-- GIN: 배열, JSONB, 전문 검색
CREATE INDEX idx_gin ON posts USING GIN (tags);
CREATE INDEX idx_jsonb ON products USING GIN (metadata jsonb_path_ops);

인덱스 상태 확인

SQL
-- 테이블의 인덱스 목록과 사용 횟수
SELECT
  indexname,
  pg_size_pretty(pg_relation_size(indexname::regclass)) AS size,
  idx_scan AS scans
FROM pg_stat_user_indexes
WHERE relname = 'orders'
ORDER BY idx_scan;

-- 사용되지 않는 인덱스 (제거 검토)
SELECT schemaname, relname, indexrelname, idx_scan
FROM pg_stat_user_indexes
WHERE idx_scan = 0 AND schemaname = 'public';

VACUUM과 통계 갱신

SQL
-- 통계 갱신 (플래너가 올바른 실행계획 선택)
ANALYZE orders;

-- VACUUM + ANALYZE
VACUUM ANALYZE orders;

-- 자동 VACUUM 상태 확인
SELECT * FROM pg_stat_user_tables WHERE relname = 'orders';
#PostgreSQL#인덱스#쿼리최적화#성능#SQL
편집 안내 · Editorial Note

이 가이드는 AI 도구를 활용해 초안을 구성하고 사람이 명령어·문맥을 검토해 발행했습니다. 운영체제와 도구 버전에 따라 결과가 달라질 수 있으므로 적용 전 공식 문서를 함께 확인하세요. 오류를 발견하시면 이메일로 제보해 주세요.

관련 공식 문서PostgreSQL 공식 문서

질문 & 답변 (Q&A)

이 가이드에 대해 궁금한 점을 질문해보세요. 확인 후 답변드립니다.