MySQL 8.4 EXPLAIN의 rows는 optimizer가 계획을 고를 때 예상한 행 수입니다. EXPLAIN ANALYZE는 설명만 하는 명령이 아니라 질의를 실행한 뒤 iterator별 실제 행 수와 시간 등을 함께 보여 줍니다.
예상 100행, 실제 4행이라면 한 예제 노드에서 추정이 실제보다 25배 큽니다. 이 차이는 통계나 데이터 분포를 조사할 단서이지, 쿼리 결과가 틀렸거나 특정 인덱스를 반드시 추가해야 한다는 증거는 아닙니다.
EXPLAIN은 계획을 추정하고 ANALYZE는 질의를 실행합니다
쿼리 계획의 rows 숫자를 실제 결과 행 수로 읽으면 안 됩니다. MySQL 8.4의 EXPLAIN은 optimizer가 질의를 어떤 계획으로 처리할지 보여 줍니다. 그 계획에 표시된 행 수는 실행 전에 세운 estimate입니다. 예를 들어 인덱스 범위 스캔 노드의 예상 값이 100이라면 optimizer가 해당 단계에서 처리할 것으로 추정한 규모를 말합니다. 실제로 100행이 반환되었다는 실행 관측값이 아닙니다.
EXPLAIN ANALYZE는 계획에 실행 측정값을 덧붙입니다. MySQL 8.4 문서는 이 명령이 문장을 실행하고 iterator마다 예상 행 수, 실제 행 수, loop 횟수, 시간 정보를 제공한다고 설명합니다. 그래서 실제 데이터에서 실행 결과를 관측하고 싶을 때 사용하지만, 본질적으로 쿼리를 실행한다는 점을 먼저 알아야 합니다. 예제에서도 읽기 전용 SELECT를 사용하며, 운영 쿼리 실행을 권하지 않습니다.
| 항목 | 예제 값 | 의미 |
|---|---|---|
| estimated rows | 100 | 실행 전 optimizer가 계산한 예상 행 수 |
| actual rows | 4 | EXPLAIN ANALYZE가 실행 중 관측한 해당 노드의 행 수 |
| loops | 1 | 이 교육용 비교의 노드 실행 횟수 |
| 추정 배수 | 25배 | 100 ÷ 4. 추정 오차 크기를 나타내는 단순 계산 |
이 표의 숫자는 개념을 설명하기 위해 만든 가상 예시입니다. MySQL 8.4 실제 실행 결과나 특정 테이블에서 측정한 값이 아닙니다. 100을 4로 나누면 estimate가 actual의 25배입니다. 이 수치는 추정이 실제보다 큰 방향과 크기를 보여 주지만, 어떤 원인이 확정되었는지는 말해 주지 않습니다. 다른 조건값, 값 분포, 통계 갱신 시점, 여러 plan node의 영향 등을 더 조사해야 합니다.
EXPLAIN
SELECT order_id
FROM sample_orders
WHERE status = 'READY';
EXPLAIN ANALYZE
SELECT order_id
FROM sample_orders
WHERE status = 'READY';계획 노드마다 같은 단위끼리 비교합니다
위 가상 SELECT가 상태 READY인 주문 id를 읽는다고 하겠습니다. EXPLAIN에서 필터 노드의 estimate가 100이라면 계획 생성 시점의 예측입니다. EXPLAIN ANALYZE를 실행해 같은 노드에서 actual 4와 loops 1을 얻었다고 가정하면, 한 번 실행에서 그 필터가 실제 네 행을 내보냈다는 관측입니다. 이 두 값을 비교할 때는 같은 노드와 같은 query 조건인지 맞춰야 합니다. 다른 테이블 스캔 노드의 200행과 최종 필터 노드의 4행을 곧바로 비교하면 안 됩니다.
여러 iterator가 연결된 계획에서는 부모와 자식 노드의 역할도 다릅니다. 자식이 읽은 행과 부모가 조건을 적용한 뒤 내보낸 행은 자연스럽게 달라질 수 있습니다. 따라서 계획을 위에서부터 한 숫자만 보는 대신 노드 이름, 조건, estimated rows, actual rows, loops를 함께 읽습니다. 오차가 처음 크게 나타나는 단계는 추가 조사에 유용한 단서가 될 수 있습니다.
측정값과 진단 조치를 분리합니다
- MySQL 버전과 어떤 SELECT 문을 비교할지 확인합니다.
EXPLAIN의 계획 노드별 estimated rows를 기록합니다.- 읽기 전용 질의에 한해
EXPLAIN ANALYZE가 실제 실행된다는 점을 확인한 후 측정값을 얻습니다. - 동일한 노드의 actual rows와 loops를 대응시킵니다.
- 추정과 실행이 크게 다른 노드를 찾고 조건값, 데이터 분포, 통계의 최신성을 조사합니다.
ANALYZE TABLE이 통계를 갱신하는 기능인지, 실제 쿼리 측정인지 구별합니다.
ANALYZE TABLE은 EXPLAIN ANALYZE와 이름이 비슷하지만 다른 명령입니다. MySQL 8.4 문서에서 ANALYZE TABLE은 키 분포 분석이나 선택적인 histogram 통계를 저장하고 optimizer의 선택에 영향을 줄 수 있다고 설명합니다. 이 명령은 데이터 자체를 조회한 실제 행 개수를 계획 출력으로 보여 주는 측정 도구가 아닙니다. 기존 통계가 최신인지 조사할 때 활용할 수 있지만, 수치 차이 하나만 보고 무조건 통계를 다시 만들 필요가 있다고 결론 내리지 마세요.
EXPLAIN ANALYZE를 무해한 설명 전용 명령으로 오해하지 않습니다
가장 큰 주의점은 EXPLAIN ANALYZE가 문장을 실행한다는 사실입니다. MySQL 8.4는 SELECT뿐 아니라 일부 UPDATE와 DELETE에도 이 명령을 허용합니다. 실제 변경문을 분석 대상으로 넣으면 데이터 변경이 일어날 수 있으므로 읽기 전용 질의인지 먼저 확인해야 합니다. 질의 실행 시간과 읽는 행 수가 커서 서비스 부하를 일으킬 가능성도 고려해야 합니다. 이 글은 문법 설명만 하며 서버나 실제 서비스 DB에 접속하지 않았습니다.
또한 estimate가 actual과 다르면 결과 데이터가 잘못됐다고 생각하기 쉽습니다. 계획 추정치는 실행 전 선택을 돕는 값이고, actual은 특정 실행에서 관측한 값입니다. 두 값의 차이는 계획의 예측 정확성에 관한 신호이지 SQL 결과의 정합성 오류를 직접 증명하지 않습니다. 먼저 어느 노드에서 차이가 생겼는지 확인하고, 그 다음에 통계와 데이터 분포를 검토하세요.
정답을 가리고 확인해 보세요
이 글을 위해 만든 학습 예시이며 공식 기출문제나 판매 카드의 인용이 아닙니다.
estimated rows=80, actual rows=5, loops=1인 MySQL 8.4 plan node에서 추정 오차는 몇 배인가요? 그 수치만으로 인덱스 추가를 확정할 수 있나요?
정답과 해설 확인
estimate는 actual의 16배입니다. 차이는 계획 추정의 진단 단서일 뿐이므로 통계, 조건값, plan node 역할 등을 더 확인하지 않고 인덱스 추가를 확정할 수 없습니다.MySQL 8.4 EXPLAIN은 계획 추정값을, EXPLAIN ANALYZE는 실제 실행의 iterator 정보를 제공합니다. ANALYZE TABLE은 통계를 관리하므로 두 명령을 구분해야 합니다.