옵티마이저가 어떤 경로로 데이터를 읽을지 정한 계획. 성능 분석은 여기서 시작한다.
왜 필요한가
같은 SQL도 실행 방법이 여러 가지다.
SELECT * FROM orders o JOIN member m ON o.member_id = m.id
WHERE m.grade = 'VIP';
- member를 먼저 걸러 orders와 조인할 수도 있고
- orders를 전부 읽어 member와 맞춰 볼 수도 있다
옵티마이저가 통계 정보를 보고 비용이 적을 것 같은 쪽을 고른다. 그 선택 결과가 실행계획이다.
무엇부터 보나 (MySQL)
EXPLAIN SELECT …;
| 컬럼 | 볼 것 |
|---|---|
type | 접근 방식. ALL(풀스캔)이면 경보 |
key | 실제 사용한 인덱스. NULL이면 못 탔다 |
rows | 읽을 것으로 예상한 행 수 |
filtered | 그중 조건을 통과할 비율(%) |
Extra | 부가 동작 |
type 등급 (좋은 순)
system > const > eq_ref > ref > range > index > ALL
↑ ↑
인덱스 풀스캔 테이블 풀스캔
Extra에서 주의할 것
Using index— 커버링 인덱스(좋음)Using filesort— 정렬을 위해 별도 작업(인덱스로 없앨 수 있는지 검토)Using temporary— 임시 테이블 생성(GROUP BY 등, 비용 큼)
추정과 실제는 다르다
EXPLAIN의 rows는 통계 기반 추정치다. 실제로 몇 행을 읽었는지 보려면
EXPLAIN ANALYZE SELECT …; -- MySQL 8.0.18+, PostgreSQL
추정과 실제가 10배 이상 차이 나면 통계가 낡은 것이다.
ANALYZE TABLE orders; -- 통계 갱신
대량 INSERT·DELETE 후 쿼리가 갑자기 느려졌다면 이걸 먼저 의심한다.
실무 진단 순서
- 느린 쿼리 로그로 대상 특정 (slow_query_log)
- EXPLAIN → type이 ALL인가? key가 NULL인가? 3. NULL이면 왜 못 탔는지 확인
-
- 조건에 함수를 씌웠나
-
- 타입이 다른가
-
- 복합 인덱스 순서가 맞나
- 인덱스를 만들거나 쿼리를 고친 뒤 다시 EXPLAIN
- EXPLAIN ANALYZE 로 실제 개선 확인
면접 답변 골격
"느린 쿼리를 만나면 추측하지 않고 실행계획부터 봅니다. 인덱스를 탔는지, 예상 행 수가 실제와 맞는지 확인하고, 못 탔다면 조건에 함수를 씌웠는지· 타입이 맞는지·복합 인덱스 순서가 맞는지를 순서대로 점검합니다."