EXPLAIN으로 MySQL 쿼리 최적화하기: 느린 쿼리 분석 완벽 가이드
EXPLAIN 명령어로 MySQL 쿼리를 분석하고 최적화하는 실전 가이드. 실행 계획 읽는 법부터 병목 지점 찾기까지 상세히 설명합니다.
럿지 AI 팀
4분 읽기
목차
EXPLAIN 완벽 가이드
EXPLAIN이란?
MySQL이 쿼리를 어떻게 실행할지 보여주는 명령어
**목적:** 느린 쿼리 원인 파악 및 최적화
기본 사용법
``
sql
EXPLAIN SELECT * FROM orders WHERE member_id = 1;
`
EXPLAIN 결과 읽기
| 컬럼 | 의미 | 중요도 |
|------|------|--------|
| type | 조인 타입 | ⭐⭐⭐ |
| key | 사용된 인덱스 | ⭐⭐⭐ |
| rows | 검사할 행 수 | ⭐⭐⭐ |
| Extra | 추가 정보 | ⭐⭐ |
type 컬럼 (조인 타입)
성능 좋음 → 나쁨 순서:
1. const (최고)
`sql
EXPLAIN SELECT * FROM members WHERE member_id = 1;
-- type: const (PK/UNIQUE 단건 조회)
`
2. eq_ref (매우 좋음)
`sql
EXPLAIN
SELECT * FROM orders o
JOIN members m ON o.member_id = m.member_id;
-- type: eq_ref (조인 시 PK/UNIQUE 사용)
`
3. ref (좋음)
`sql
EXPLAIN SELECT * FROM orders WHERE member_id = 1;
-- type: ref (인덱스 사용, 여러 행 가능)
`
4. range (괜찮음)
`sql
EXPLAIN SELECT * FROM orders
WHERE order_date BETWEEN '2024-01-01' AND '2024-12-31';
-- type: range (범위 검색)
`
5. index (나쁨)
`sql
EXPLAIN SELECT member_id FROM orders;
-- type: index (인덱스 풀 스캔)
`
6. ALL (최악)
`sql
EXPLAIN SELECT * FROM orders WHERE total_amount > 10000;
-- type: ALL (테이블 풀 스캔!)
`
key 컬럼 (사용된 인덱스)
NULL = 인덱스 미사용
`sql
EXPLAIN SELECT * FROM orders WHERE total_amount > 10000;
-- key: NULL (인덱스 없음!)
-- 해결: 인덱스 추가
CREATE INDEX idx_amount ON orders(total_amount);
EXPLAIN SELECT * FROM orders WHERE total_amount > 10000;
-- key: idx_amount (인덱스 사용!)
`
rows 컬럼 (검사 행 수)
많을수록 느림
`sql
-- 나쁨
EXPLAIN SELECT * FROM orders;
-- rows: 1,000,000
-- 좋음
EXPLAIN SELECT * FROM orders WHERE order_id = 1;
-- rows: 1
`
Extra 컬럼
Using filesort (나쁨)
`sql
EXPLAIN SELECT * FROM orders ORDER BY total_amount;
-- Extra: Using filesort (정렬 비용 큼)
-- 해결: 인덱스 추가
CREATE INDEX idx_amount ON orders(total_amount);
`
Using temporary (나쁨)
`sql
EXPLAIN SELECT member_id, COUNT(*)
FROM orders GROUP BY member_id;
-- Extra: Using temporary (임시 테이블 사용)
`
Using index (좋음)
`sql
EXPLAIN SELECT member_id FROM orders WHERE member_id = 1;
-- Extra: Using index (커버링 인덱스!)
`
Using where (보통)
`sql
EXPLAIN SELECT * FROM orders WHERE total_amount > 10000;
-- Extra: Using where (WHERE 조건 필터링)
`
실전 최적화 예제
Before: 느린 쿼리
`sql
SELECT * FROM orders
WHERE status = 'PAID'
ORDER BY order_date DESC
LIMIT 10;
EXPLAIN:
- type: ALL
- key: NULL
- rows: 1,000,000
- Extra: Using filesort
-- 실행 시간: 5초
`
After: 최적화
`sql
-- 복합 인덱스 생성
CREATE INDEX idx_status_date ON orders(status, order_date DESC);
EXPLAIN:
- type: ref
- key: idx_status_date
- rows: 100
- Extra: Using index
-- 실행 시간: 0.01초 (500배 향상!)
`
N+1 문제 찾기
문제
`sql
-- 주문 100개 조회
SELECT * FROM orders LIMIT 100;
-- 각 주문마다 회원 정보 조회 (100번!)
SELECT * FROM members WHERE member_id = ?;
`
해결: JOIN 사용
`sql
SELECT o.*, m.*
FROM orders o
LEFT JOIN members m ON o.member_id = m.member_id
LIMIT 100;
-- 쿼리 1번으로 해결!
`
EXPLAIN ANALYZE (MySQL 8.0+)
실제 실행 시간까지 측정
`sql
EXPLAIN ANALYZE
SELECT * FROM orders WHERE member_id = 1;
-- 결과:
-- actual time=0.050..0.053 rows=10 loops=1
`
슬로우 쿼리 로그
활성화
`sql
-- my.cnf
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1 -- 1초 이상 걸리는 쿼리 기록
`
분석
`bash
mysqldumpslow /var/log/mysql/slow.log
가장 느린 쿼리 Top 10
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
`
최적화 체크리스트
1. WHERE 절
- [ ] 인덱스 있는 컬럼 사용
- [ ] 함수 사용 피하기 (WHERE YEAR(date) ✗)
- [ ] LIKE는 앞부분 일치만 ('홍%' ✓, '%홍%' ✗)
2. JOIN
- [ ] 조인 컬럼에 인덱스
- [ ] 불필요한 JOIN 제거
- [ ] LEFT JOIN보다 INNER JOIN (가능하면)
3. ORDER BY
- [ ] 인덱스 활용
- [ ] LIMIT과 함께 사용
4. SELECT
- [ ] SELECT *` 피하기- [ ] 필요한 컬럼만 조회
더 배우기
김영한의 실전 데이터베이스
- 쿼리 최적화 심화
- 실전 성능 튜닝
- 대용량 처리
---
**태그**: #EXPLAIN #MySQL최적화 #쿼리분석 #성능튜닝 #실행계획
L
럿지 AI 팀
AI 기술과 비즈니스 혁신을 선도하는 럿지 AI의 콘텐츠 팀입니다.
관련 포스트
뉴스
2025 데이터베이스 시장 전망: MySQL이 여전히 1위, 클라우드 DB 급성장
2025년 데이터베이스 시장 분석. MySQL 점유율 1위 유지, AWS RDS·Azure DB 등 클라우드 DB 시장 연 25% 성장.
•4분 읽기
튜토리얼
B2B SEO 완벽 가이드: 의사결정권자를 검색으로 확보하는 법
B2B 기업을 위한 SEO 전략. 영업 없이 리드를 자동으로 확보하는 검색 최적화 완벽 가이드입니다.
•1분 읽기
튜토리얼
백링크 완벽 가이드: 초보자도 이해하는 SEO의 핵심
백링크가 무엇인지, 왜 중요한지, 어떻게 만들어야 하는지 초보자도 쉽게 이해할 수 있도록 완벽 정리한 가이드입니다.
•4분 읽기