본문 바로가기

업무 자동화 · 도구 검증 · 서비스 운영

반복 업무를 줄이는 방법,
직접 시험하고 기록합니다.

예약 명단 정리부터 알림 자동화, 앱 운영까지.
원본 예제와 확인표, 실험 결과를 함께 나눕니다.

첫 번째 실험 · 예약 명단

이름이 같으면
같은 예약일까요?

B102 · 방문자B9월 10일
B103 · 방문자B9월 11일

다른 예약입니다. 둘 다 남겨야 합니다.

가상 명단 12행으로 확인한 결과 →
개발 문제 해결

MySQL EXPLAIN 보는 법: type·key·rows 읽는 순서

by 코딩히어로 2026. 9. 12.
300x250
반응형

MySQL 조회가 오래 걸릴 때는 EXPLAIN으로 실행 계획부터 확인할 수 있습니다. 처음에는 table, type, possible_keys, key, rows, Extra를 순서대로 읽으면 됩니다. 이때 rows는 실제 조회 건수가 아니라 옵티마이저가 추정한 검사 행 수입니다.

이 글은 MySQL 8.4 공식 매뉴얼 기준입니다. 운영 데이터베이스에서 쿼리를 실행하거나 성능을 측정한 결과는 아닙니다. 예제의 테이블과 인덱스 이름은 설명용이며 실제 테이블 구조에 맞게 바꿉니다.

1. 표 형태로 실행 계획 출력하기

EXPLAIN FORMAT=TRADITIONAL
SELECT id, created_at
FROM qa_orders
WHERE customer_id = 12
ORDER BY created_at DESC
LIMIT 20;

FORMAT=TRADITIONAL을 적어 표 형태를 명시했습니다. 기본 출력 형식은 서버 설정의 영향을 받을 수 있습니다. 먼저 어떤 테이블에서, 어떤 조건으로, 어떤 정렬을 요청하는지 쿼리 자체를 읽고 실행 계획과 나란히 놓습니다.

SQL 문법 오류 때문에 실행 계획이 나오지 않는다면 MySQL 1064의 오류 위치 확인부터 진행하세요. 문법 확인과 조회 경로 분석은 단계가 다릅니다.

2. type과 key를 먼저 연결해서 읽기

열 확인할 질문
table 어느 테이블의 접근 단계인가?
type 어떤 방식으로 행을 찾는가?
possible_keys 행을 찾는 데 후보가 되는 인덱스는?
key 실제로 선택한 인덱스는?
rows 검사할 것으로 추정한 행 수는?
Extra 추가 필터링·정렬 정보가 있는가?

type=ALL은 전체 테이블 스캔, type=range는 범위 접근을 뜻합니다. type=ref는 인덱스의 비교 조건에 맞는 여러 행을 찾을 수 있는 접근입니다. 이름 하나만으로 쿼리 전체의 속도를 확정할 수는 없습니다. 작은 테이블에서는 전체 스캔이 선택될 수도 있습니다.

possible_keys에 인덱스가 있어도 key에는 다른 값이나 NULL이 나올 수 있습니다. 후보 목록과 선택 결과를 구분해야 합니다. 또 key가 표시되어도 전체 인덱스를 훑는 type=index라면 읽는 양을 함께 확인합니다.

SHOW INDEX FROM qa_orders;

SHOW INDEX에서 인덱스에 포함된 열과 순서를 확인합니다. 쿼리 조건과 일치하는 이름만 찾기보다 실제 인덱스 열 구성을 읽는 것이 다음 판단에 도움이 됩니다.

3. rows는 추정값, 실제 시간은 별도

다음 숫자는 읽는 방법을 설명하기 위한 가상 예시입니다. 측정 결과나 개선 전후 수치가 아닙니다.

가상 실행 계획 값 해석
rows=1000 이 접근에서 검사할 행을 약 1,000개로 추정
filtered=10.00 조건을 통과할 비율을 약 10%로 추정
1000 × 10% 다음 단계로 약 100개가 이어질 것으로 추정

InnoDB에서 rows는 추정치이며 실제 행 수와 다를 수 있습니다. 조인 쿼리는 앞 단계에서 몇 번 반복되는지도 함께 읽어야 합니다. rows가 줄었다는 이유만으로 사용자 응답 시간이 같은 비율로 줄었다고 표현할 수는 없습니다.

LIMIT 20도 검사할 행을 항상 20개로 제한한다는 뜻은 아닙니다. 조건에 맞는 행을 찾고 정렬하는 과정에서 더 많은 행을 읽을 수 있습니다. 정렬과 조건을 인덱스로 처리할 수 있는지에 따라 계획이 달라집니다.

4. Extra와 EXPLAIN ANALYZE 구분하기

표시 읽는 방법
Using where 조건으로 행을 필터링함
Using index 필요한 열을 인덱스에서 읽을 수 있는 접근
Using filesort 인덱스 순서만으로 끝내지 못한 추가 정렬

Using filesort라는 이름만으로 디스크 정렬이 발생했다고 단정할 수는 없습니다. 추가 정렬을 한다는 뜻으로 읽고, 데이터 양과 실행 조건을 함께 확인합니다. Using index도 인덱스를 사용한 모든 상황에 붙는 일반 표시와 구분해야 합니다.

EXPLAIN ANALYZE
SELECT id, created_at
FROM qa_orders
WHERE customer_id = 12
ORDER BY created_at DESC
LIMIT 20;

EXPLAIN ANALYZE는 쿼리를 실제 실행하고 시간·행 수·반복 횟수 정보를 제공합니다. 따라서 일반 EXPLAIN처럼 계획만 확인하는 명령으로 취급하면 안 됩니다. 위 예제도 테스트 데이터베이스에서 부하와 권한을 확인한 다음 사용합니다. 이 글에서는 실행하지 않았습니다.

인덱스를 추가할지는 조회 조건뿐 아니라 정렬, 데이터 분포, 쓰기 비용까지 보고 결정합니다. 조건 열이 customer_id와 created_at이라고 해서 모든 환경에서 같은 복합 인덱스가 선택되지는 않습니다. 저장 방식의 배경은 InnoDB와 MySQL의 관계를 참고할 수 있습니다.

자주 묻는 질문

key가 NULL이면 바로 인덱스를 추가하나요?

먼저 테이블 크기, 조건의 선택도, 기존 인덱스 열 순서를 확인합니다. 옵티마이저가 전체 스캔을 선택한 이유를 살핀 뒤 테스트 환경에서 후보를 비교합니다.

EXPLAIN과 EXPLAIN ANALYZE의 숫자가 달라도 되나요?

하나는 추정 계획을, 다른 하나는 실제 실행 정보를 포함합니다. 차이가 크면 데이터 분포와 통계 상태를 살펴볼 근거가 됩니다. 같은 데이터와 조건으로 비교해야 의미가 있습니다.

MySQL 5.7에서도 ANALYZE를 쓸 수 있나요?

EXPLAIN ANALYZE는 MySQL 8.0.18에서 도입됐습니다. 5.7에서는 같은 문법을 사용할 수 없습니다. MariaDB 역시 지원 문법과 출력 의미를 해당 제품 문서로 따로 확인합니다.

근거: MySQL EXPLAIN 문법, 실행 계획 출력의 의미. 본문의 수치는 해석용 예시이며, 인덱스 생성이나 운영 쿼리 실행은 수행하지 않았습니다.

300x250
반응형

댓글