#10 - EXPLAIN ANALYZE 제대로 읽기
중년개발자
@loxo
9일 전

PostgreSQL 성능 문제의 90%는 여기서 시작해서 여기서 끝난다
EXPLAIN ANALYZE는 처음 보면 외계어처럼 느껴지기 쉽다.
하지만 관점을 조금만 바꾸면, 이건 DB가 직접 써주는 성적표에 가깝다.
이 글에서는 **"모든 숫자를 이해하려 하지 말고, 무엇을 먼저 봐야 하는지"**에 집중한다.
QUERY PLAN |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------+
Nested Loop (cost=0.42..14.33 rows=69 width=563) (actual time=0.087..0.198 rows=52 loops=1) |
-> Index Only Scan using boards_pkey on boards b (cost=0.14..2.36 rows=1 width=16) (actual time=0.052..0.054 rows=1 loops=1) |
Index Cond: (id = '019baab4-6b61-7d6d-a9c3-95edf906f976'::uuid) |
Heap Fetches: 1 |
-> Index Scan using posts_p1_board_id_category_is_pinned_id_idx on posts_p1 p (cost=0.27..11.28 rows=69 width=563) (actual time=0.025..0.084 rows=52 loops=1)|
Index Cond: (board_id = '019baab4-6b61-7d6d-a9c3-95edf906f976'::uuid) |
Planning Time: 1.419 ms |
Execution Time: 0.268 ms |1. EXPLAIN ANALYZE는 무엇을 해주는 도구인가
간단히 말하면:
- EXPLAIN → DB가 이렇게 실행할 거야 라고 미리 말해주는 것
- EXPLAIN ANALYZE → 진짜로 실행해보고 결과를 알려주는 것
EXPLAIN ANALYZE
SELECT * FROM orders WHERE user_id = 10;이 명령을 실행하면 PostgreSQL은:
- 실제로 쿼리를 실행하고
- 어떤 방식으로 실행했는지
- 얼마나 시간이 걸렸는지
- 예상과 실제가 얼마나 달랐는지
를 전부 보여준다.
👉 그래서 성능 분석할 때는 EXPLAIN ANALYZE가 기본이다
2. 가장 먼저 봐야 할 것 3가지
처음부터 모든 항목을 이해하려고 하면 바로 포기하게 된다.
아래 3가지만 먼저 보면 된다.
1️⃣ 실행 시간 (Execution Time)
Execution Time: 120.345 ms- 이 쿼리가 얼마나 걸렸는지
- 느린지 빠른지 판단하는 기준
일반적인 체감 기준:
- 10ms 이하 → 매우 빠름
- 10~100ms → 보통
- 100ms 이상 → 개선 대상
2️⃣ 실제 처리된 행 수 (rows)
rows=5이 숫자는 DB가 실제로 읽은 행의 개수다.
- rows가 많다 → 많이 읽었다 → 느릴 가능성 큼
- rows가 적다 → 효율적인 실행
👉 인덱스를 잘 탔는지 판단하는 핵심 지표
3️⃣ Scan 방식 (Seq Scan vs Index Scan)
EXPLAIN을 보면 이런 단어들이 보인다.
Seq Scan on orders
Index Scan using idx_orders_user_id의미는 단순하다.
- Seq Scan: 테이블을 처음부터 끝까지 읽음
- Index Scan: 인덱스를 통해 필요한 것만 읽음
흔히 하는 오해:
Seq Scan = 무조건 나쁨 ❌
사실은:
- 테이블이 작으면 Seq Scan이 더 빠를 수도 있다
- 중요한 건 얼마나 많은 rows를 읽었는가
3. cost를 어떻게 이해해야 하는가
EXPLAIN에 항상 나오는 이것:
cost=0.00..431.00이 단계에서는 이렇게 이해하는 것이 가장 현실적이다.
- cost는 DB 내부 추정치 (CPU 연산과 디스크 접근을 가중치로 계산한 PostgreSQL 내부 점수로, 실행 계획을 고르기 위해 사용된다)
- 절대적인 시간(ms)이 아님
- 다른 쿼리와 직접 비교하면 안 됨
👉 우선은 Execution Time과 rows에 집중하는 것이 가장 효율적이다
4. 예상(rows)과 실제(rows)가 다르면 위험 신호
rows=10 (actual rows=5000)이런 경우는 매우 중요하다.
의미:
- DB는 10건 나올 줄 알고 실행했는데
- 실제로는 5000건이 나왔다
이러면:
- 실행 계획이 잘못 선택될 수 있고
- 갑자기 쿼리가 느려질 수 있다
주요 원인:
- 통계 정보 오래됨
- VACUUM / ANALYZE 부족
- 데이터 분포가 한쪽으로 쏠림
5. 위에서 아래로 읽지 말 것
많이 하는 실수:
EXPLAIN 결과를 위에서부터 차례대로 읽는다
하지만 실제 실행 순서는 아래에서 위다.
- 맨 아래 → 실제 데이터 접근
- 맨 위 → 최종 결과 반환
👉 아래쪽이 진짜 중요한 부분
6. EXPLAIN ANALYZE 체크 순서
실무에서 이렇게만 봐도 된다.
- Execution Time이 느린가?
- rows가 예상보다 너무 많은가?
- Seq Scan이 나왔는데 테이블이 큰가?
- 인덱스가 있는데 Index Scan을 안 타는가?
- 예상 rows와 실제 rows 차이가 큰가?
이 중 하나라도 걸리면 → 개선 대상
7. EXPLAIN ANALYZE는 죄를 묻는 도구가 아니다
중요한 마인드셋 하나.
EXPLAIN ANALYZE는
"이 쿼리는 왜 이렇게 실행됐는지"
이유를 알려주는 도구다.
- 잘못을 찾는 게 아니라
- 이해를 쌓는 과정
처음엔 못 읽는 게 정상이다.
자주 보다 보면 패턴이 보이기 시작한다.