실행 계획(Execution Plan)은 데이터베이스 쿼리 옵티마이저가 쿼리를 실행하는 방법을 단계별로 나타낸 계획이다. EXPLAIN 명령으로 확인할 수 있으며, 느린 쿼리의 원인을 파악하고 최적화하는 데 필수적인 도구다.
sql
-- 기본 EXPLAIN (실제 실행 X)
EXPLAIN SELECT * FROM orders WHERE user_id = 100;
-- EXPLAIN ANALYZE (실제 실행 + 측정)
EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 100;
-- EXPLAIN ANALYZE BUFFERS (버퍼 캐시 정보 포함)
EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON)
SELECT o.*, u.name
FROM orders o JOIN users u ON o.user_id = u.id
WHERE o.created_at > '2024-01-01';
실행 계획 읽는 법
EXPLAIN ANALYZE 결과:
Hash Join (cost=42.05..1234.56 rows=500 width=80)
(actual time=1.234..5.678 rows=487 loops=1)
Hash Cond: (o.user_id = u.id)
-> Seq Scan on orders o (cost=0.00..890.00 rows=10000)
Filter: (created_at > '2024-01-01')
Rows Removed by Filter: 9513
-> Hash (cost=30.00..30.00 rows=1000)
-> Seq Scan on users u
핵심 지표:
cost=시작비용..전체비용 rows=예상행수 width=행크기(bytes)
actual time=실제시작..실제종료 rows=실제행수 loops=반복횟수
노드 유형
| 노드 | 설명 | 성능 |
|---|
| Seq Scan | 전체 테이블 스캔 | 작은 테이블 또는 대량 조회 시 적합 |
| Index Scan | 인덱스 이용 랜덤 읽기 | 선택적 조회에 적합 |
| Index Only Scan | 인덱스만으로 결과 반환 (커버링 인덱스) | 매우 빠름 |
| Bitmap Index Scan | 비트맵 이용 배치 읽기 | 중간 선택도에 적합 |
| Nested Loop | 행마다 내부 루프 | 소량 조인 |
| Hash Join | 해시 테이블 빌드 후 조인 | 대량 동등 조인 |
| Merge Join | 정렬된 두 집합 병합 | 정렬된 대량 조인 |
문제 패턴 식별
sql
-- 문제: Seq Scan on large table
Seq Scan on orders (cost=0..890000 rows=10000000)
→ 해결: 적절한 인덱스 추가
-- 문제: 예측 행수(rows) vs 실제 행수(actual rows) 큰 차이
Seq Scan on orders (rows=1000) (actual rows=500000)
→ 해결: ANALYZE orders; (통계 갱신)
-- 문제: Nested Loop with many loops
Nested Loop (loops=50000)
→ 해결: Hash Join으로 변경 유도, 조인 조건 확인
sql
EXPLAIN SELECT * FROM orders WHERE user_id = 100;
-- type 컬럼 중요:
-- ALL: Full Table Scan (나쁨)
-- ref: 인덱스 사용
-- eq_ref: 유일 인덱스 (좋음)
-- const: 상수 비교 (최고)
관련 개념