2 min read

PostgreSQL 피드 조회 인덱스 튜닝

복합 인덱스와 실행 계획 해석으로 피드 API 지연을 줄이는 쿼리 최적화 가이드

PostgreSQL 피드 조회 인덱스 튜닝 thumbnail

도입

피드 API 성능 이슈는 보통 트래픽 증가보다 쿼리 패턴 변화에서 먼저 나타난다. 기능이 추가되면서 정렬 조건과 필터 조건이 조금씩 늘고, 어느 순간 인덱스가 쿼리를 따라가지 못한다. 이때 단순히 인덱스를 더 만드는 방식은 오히려 쓰기 비용만 키운다.

이 글은 "어떤 인덱스를 왜 만들었는지"를 실행 계획으로 검증하는 실무 절차를 정리한다.

PostgreSQL 피드 조회 인덱스 튜닝 커버
Wikimedia Commons 기반 무료 이미지

문제 정의

피드 조회에서 자주 터지는 병목은 아래 4가지다.

  • OFFSET 기반 페이지네이션으로 뒷페이지 응답 시간이 급증한다.
  • 다중 필터(status, published_at, author_id) 조합에서 인덱스 선택이 비효율적이다.
  • 커버링 인덱스가 없어 heap fetch가 과도하게 발생한다.
  • 인덱스 추가 후에도 EXPLAIN ANALYZE 검증 없이 배포한다.

핵심은 keyset pagination + 복합 인덱스 + 실제 계획 검증을 한 세트로 보는 것이다.

핵심 개념

항목잘못된 접근권장 접근
페이지네이션OFFSET n LIMIT 20keyset (WHERE (published_at,id) < (...))
인덱스 설계조건마다 단일 인덱스 추가조회 패턴 기준 복합 인덱스
검증개발환경 추정치만 확인프로덕션 유사 데이터로 EXPLAIN ANALYZE
모니터링평균 응답 시간만 확인p95 + rows scanned + shared hit ratio

코드 예시 1: 피드 조회용 복합 인덱스 + keyset 쿼리

CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_posts_feed
ON posts (status, published_at DESC, id DESC)
INCLUDE (title, author_id, summary);

-- cursor: (published_at, id)
SELECT id, title, author_id, summary, published_at
FROM posts
WHERE status = 'published'
  AND (published_at, id) < ($1::timestamptz, $2::bigint)
ORDER BY published_at DESC, id DESC
LIMIT 20;

코드 예시 2: 실행 계획 회귀 체크

EXPLAIN (ANALYZE, BUFFERS, VERBOSE)
SELECT id, title, author_id, summary, published_at
FROM posts
WHERE status = 'published'
  AND (published_at, id) < ('2026-03-01T00:00:00Z', 982341)
ORDER BY published_at DESC, id DESC
LIMIT 20;

-- 목표 예시
-- Index Scan using idx_posts_feed on posts
-- Buffers: shared hit 비율 높음
-- actual time: < 10ms (warm cache)

아키텍처 흐름

Mermaid diagram rendering...

트레이드오프

  • keyset pagination은 빠르지만 임의 페이지 점프 UX가 약하다.
  • INCLUDE 인덱스는 조회 성능에 유리하지만 저장 공간을 더 사용한다.
  • 인덱스가 늘수록 쓰기 비용이 증가하므로 "조회 패턴 우선순위"가 중요하다.

정리

피드 성능 최적화는 인덱스를 많이 만드는 작업이 아니다. 조회 패턴을 기준으로 인덱스를 설계하고, 실행 계획으로 효과를 검증하는 반복 루프다. 이 루프를 CI나 배포 체크리스트에 넣으면 성능 회귀를 사전에 차단할 수 있다.

이미지 출처

  • Cover: source link
  • License: LGPL / Author: The Oxygen Team , KDE ;
  • Note: Wikimedia Commons 무료 라이선스 이미지를 다운로드 후 1600px 기준 JPG로 최적화했습니다.

댓글