VillageSQL is a drop-in replacement for MySQL with extensions.
All examples on this page work on VillageSQL. Install Now →
EXPLAIN입니다. MySQL이 쿼리를 어떻게 실행할 계획인지 정확히 보여줍니다 — 어떤 인덱스를 사용하는지, 몇 행을 스캔할 것으로 예상하는지, 어디서 비싼 작업을 하는지. 읽을 수 있게 되면 거의 모든 느린 쿼리를 고칠 수 있습니다.
EXPLAIN 실행하기
아무SELECT 앞에 EXPLAIN을 붙이세요:
중요한 열
전체EXPLAIN 행은 다음과 같습니다:
type — MySQL이 테이블을 스캔하는 방식
가장 중요한 열입니다. 접근 방법을 알려주며, 가장 빠른 것부터 가장 느린 것 순으로:
ALL이 고쳐야 할 것입니다. MySQL이 테이블의 모든 행을 읽고 있다는 뜻입니다. 백만 행짜리 테이블에서는 쿼리 실행마다 백만 번의 읽기입니다.
key — MySQL이 선택한 인덱스
NULL은 인덱스를 사용하지 않았다는 뜻입니다. possible_keys에 인덱스가 나열되어 있는데 key가 NULL이면, MySQL이 전체 스캔이 더 싸다고 판단한 것입니다 — 보통 테이블이 작거나 쿼리의 선택도가 충분하지 않기 때문입니다.
rows — 검사할 것으로 추정되는 행 수
보장이 아니라 추정치입니다. MySQL은 통계를 사용해 이 숫자를 만듭니다. rows: 1인 쿼리는 빠르고, 프로덕션 테이블에서 rows: 5000000은 문제입니다.
Extra — 추가 실행 세부 정보
Extra 열에는 중요한 플래그가 들어 있습니다:
큰 테이블에서
Using filesort와 Using temporary가 함께 나오면 위험 신호입니다.
실습 예제
ALL)과 filesort입니다. 복합 인덱스로 둘 다 고치세요(인덱스 설계 원칙은 MySQL 인덱스의 동작 방식을 보세요):
rows가 1,000,000에서 4,200으로 떨어졌습니다. type은 이제 ref — status에 대한 동등 조회입니다. 인덱스가 이미 각 status 값 안에서 행을 created_at 순으로 정렬하기 때문에 filesort가 사라졌습니다.
EXPLAIN ANALYZE
EXPLAIN ANALYZE는 쿼리를 실제로 실행하고 추정치와 함께 실제 시간을 반환합니다:
cost와 rows는 옵티마이저의 추정치입니다. actual time과 actual rows는 실제로 일어난 일입니다. 추정 행 수와 실제 행 수 사이의 큰 차이는 오래된 통계를 뜻합니다 — ANALYZE TABLE orders를 실행해 갱신하세요.
자주 묻는 질문
EXPLAIN과 커버링 인덱스의 관계는 무엇인가요?
Extra: Using index는 MySQL이 커버링 인덱스를 사용하고 있다는 뜻입니다 — 테이블 행을 읽지 않고 인덱스만으로 쿼리에 답할 수 있습니다. 읽기가 많은 테이블에서 가장 효과가 큰 최적화 중 하나입니다. 설계 방법은 MySQL의 커버링 인덱스를 보세요.
내 쿼리에 type: index가 나옵니다 — 괜찮은가요?
별로 그렇지 않습니다. type: index는 MySQL이 (테이블 대신) 전체 인덱스를 스캔했다는 뜻으로, ALL보다 빠르지만 여전히 전체 스캔입니다. 쿼리가 모든 행을 필요로 하지만 인덱스에서 그것을 충족할 수 있을 때 나타납니다. 큰 테이블에서 이것을 만난다면, 커버링 인덱스나 WHERE 절로 스캔 범위를 좁힐 수 있는지 확인하세요.
MySQL은 왜 내가 만든 인덱스를 무시하나요?
옵티마이저는 통계를 바탕으로 인덱스를 선택합니다. 테이블이 작으면 MySQL은 전체 스캔이 더 싸다고 판단할 수 있습니다. 통계가 오래되었으면 인덱스의 선택도를 과소평가할 수 있습니다.ANALYZE TABLE을 실행해 통계를 새로 고친 뒤 EXPLAIN을 다시 확인하세요.
INSERT, UPDATE, DELETE에 EXPLAIN을 사용할 수 있나요?
예 — MySQL 8.0 이상에서EXPLAIN은 모든 DML 문에 동작합니다. 출력은 수정될 행에 대한 접근 방법을 보여주며, UPDATE나 DELETE가 느릴 때 유용합니다.
어떤 쿼리를 먼저 EXPLAIN할지 찾아야 한다면, MySQL 슬로우 쿼리 로그가 서버에서 가장 느린 쿼리를 수집하고 총 시간순으로 순위를 매깁니다.
문제 해결
함께 보기
- MySQL 인덱스의 동작 방식 — EXPLAIN이 보고하는 B-트리 구조
- MySQL의 커버링 인덱스 — Extra의
Using index가 뜻하는 것과 거기에 도달하는 방법 - MySQL 슬로우 쿼리 로그 — EXPLAIN을 실행할 가치가 있는 쿼리 찾기
- 내 MySQL 쿼리는 왜 느린가요? — EXPLAIN이 입력이 되는 튜닝 워크플로
- MySQL의 페이지네이션: 키셋 대 OFFSET — 키셋 페이지네이션이 스캔 대신 탐색하는지 확인하기
- MySQL LIMIT — 튜토리얼에서 설명하는 실행 계획 행 하나