판단
| # |
기준 |
설명 |
| 1 |
해당 API가 목표 p95를 넘었는가? |
이미 넘었거나, 마진이 작아 VU 증가 시 초과 가능한가 |
| 2 |
그 API가 읽기 중심이고 반복 호출되는가? |
SELECT 쿼리, 높은 req/s |
| 3 |
느린 이유가 DB 조회/정렬/집계/검색 때문인가? |
인덱스 부재, Full Scan, JOIN+GROUP BY 등 |
| 4 |
데이터 최신성이 얼마나 중요하고, 변경 빈도는 낮은가? |
캐싱 적합성 판단 |
| 5 |
인덱스/캐시 적용 후 같은 조건에서 p95, DB CPU, 쿼리 시간이 개선됐는가? |
적용 후 동일 조건 재측정 필요 (Before/After) |
요약
| 순위 |
API |
적용 방법 |
핵심 근거 |
| 1 |
content-list |
인덱싱 + 캐싱 |
Postgres CPU 86% (최고), 인덱스 0개, 읽기 127 req/s |
| 2 |
playlist-detail |
캐싱 |
p95 271ms (목표 300ms 근소), pending 28건, 4개 쿼리 연쇄 |
| 3 |
playlist-list |
캐싱 (또는 반정규화) |
커넥션 풀 포화, JOIN+GROUP BY 집계 매 요청 실행 |
| 4 |
review-list |
인덱싱 |
목록 조회용 복합 인덱스 부재, 쿼리 패턴이 명확 |
1. content-list (콘텐츠 목록 조회) — 인덱싱 + 캐싱
테스트 결과
| 지표 |
값 |
비고 |
| p95 |
215ms |
목표 500ms 이내 |
| Postgres CPU |
86% |
9개 API 중 최고 |
| App CPU |
135% |
|
| 커넥션 풀 |
active 4/10, pending 0 |
|
| 처리량 |
127 req/s |
|
기준별 판단
| 기준 |
판단 |
근거 |
| p95 목표 초과? |
아님 |
p95 215ms로 목표 이내이나, Postgres CPU 86%는 VU 증가 또는 데이터 증가 시 급격한 성능 저하 예고 |
| 읽기 중심 + 반복 호출? |
YES |
127 req/s, 순수 SELECT, 목록 화면 진입마다 호출 |
| 느린 이유가 DB? |
YES |
contents 테이블에 인덱스가 하나도 없음. deleted_at IS NULL 필터 + watcher_count/average_rating/created_at 정렬을 Sequential Scan + Sort로 처리 |
| 데이터 최신성/변경 빈도? |
캐싱 적합 |
콘텐츠 등록은 관리자 행위로 빈도 낮음. 30~60초 TTL 캐시 가능 |
현재 쿼리문
파일: ContentQdslRepositoryImpl.java - findContents()
WHERE deleted_at IS NULL
AND type = ? (선택)
ORDER BY watcher_count DESC, id (또는 average_rating, created_at)
- 기존 인덱스: 없음
- Full Scan + Sort 발생 → Postgres CPU 86%의 직접 원인
최적화 방안
인덱싱: 정렬 기준별 Partial 복합 인덱스
-- 시청자 수 정렬 (기본)
CREATE INDEX idx_contents_active_watcher
ON contents (watcher_count DESC, id)
WHERE deleted_at IS NULL;
-- 평균 평점 정렬
CREATE INDEX idx_contents_active_rating
ON contents (average_rating DESC, id)
WHERE deleted_at IS NULL;
-- 최신순 정렬
CREATE INDEX idx_contents_active_created
ON contents (created_at DESC, id)
WHERE deleted_at IS NULL;