← 아티클 목록

EXPLAIN ANALYZE 보는 법 — 실제 실행시간 읽기

2027-09-13#database#MySQL#성능

EXPLAIN은 옵티마이저의 **계획(추정)**을 보여주지만, 그 계획이 실제로 빠른지는 알려주지 않습니다. EXPLAIN ANALYZE(MySQL 8.0.18+)는 쿼리를 실제로 실행한 뒤 각 단계에 걸린 시간과 처리한 행 수를 돌려줍니다. 추정과 실제가 얼마나 어긋났는지가 병목의 핵심 단서입니다.

SQL
EXPLAIN ANALYZE
SELECT * FROM orders WHERE user_id = 42 AND status = 'paid';

출력에서 읽는 4가지 수치

각 노드는 (cost=... rows=...) (actual time=A..B rows=R loops=L) 형태로 나옵니다. 앞은 추정, 뒤 actual이 실제 측정값입니다.

수치의미보는 법
actual time=A..BA=첫 행까지 ms, B=마지막 행까지 msB가 큰 노드가 실제 병목
rows=R실제 반환 행 수추정 rows와 크게 다르면 통계 부정확
loops=L이 노드가 반복 실행된 횟수조인 안쪽에서 loops가 크면 비용 폭증
actual time 합산자식 노드 시간 포함부모-자식 시간 차이가 그 단계 순수 비용

핵심은 추정 rows와 실제 rows의 괴리입니다. 옵티마이저가 100행을 예상했는데 실제 50만 행이면, 잘못된 통계로 엉뚱한 실행계획을 골랐다는 신호입니다.

실제 실행시간으로 병목 찾기

  1. 출력의 가장 안쪽(들여쓰기 깊은) 노드부터 읽습니다. 실행은 안에서 밖으로 진행됩니다.
  2. actual time=...B 값이 가장 큰 노드를 찾습니다. 그 노드가 전체 시간을 잡아먹는 곳입니다.
  3. 그 노드에서 loops가 1보다 크면, 실제 단일 비용은 B이지만 총 비용은 대략 B × loops입니다. 중첩 루프 조인의 안쪽이 흔한 범인입니다.
  4. 추정 rows와 실제 rows 차이가 10배 이상이면 ANALYZE TABLE <테이블>로 통계를 갱신합니다.
  5. Table scan on orders 같은 노드가 실제 시간 대부분을 차지하면, 인덱스 부재가 원인입니다.
SQL
-- 통계가 어긋났을 때
ANALYZE TABLE orders;
-- 다시 측정
EXPLAIN ANALYZE SELECT ...;

EXPLAIN ANALYZE는 쿼리를 실제로 실행하므로 UPDATE/DELETE에는 신중히 써야 합니다(트랜잭션 내에서 롤백 권장).

요점 정리

  • EXPLAIN ANALYZE는 추정이 아닌 실측 시간·행 수를 준다.
  • 들여쓰기 깊은 노드부터, actual time 끝값이 큰 곳이 병목.
  • 추정 rows와 실제 rows가 크게 다르면 통계를 ANALYZE TABLE로 갱신.
  • loops가 큰 조인 안쪽 노드는 단일 비용이 작아도 총합이 폭증한다.

실행계획을 직접 측정하고 인덱스 전후의 actual time 변화를 비교하는 실습은 데이터베이스 트랙에서 회원가입 없이 무료로 할 수 있습니다.