EXPLAIN показує план і оцінки оптимізатора. Запит не виконується.
EXPLAIN ANALYZE (MySQL 8.0.18+) виконує запит і показує план разом з фактичними вимірами: скільки рядків пройшло через кожен вузол, скільки часу він зайняв, скільки разів виконувався. Вивід завжди у форматі TREE.
EXPLAIN ANALYZE
SELECT u.name, COUNT(*) FROM users u
JOIN orders o ON o.user_id = u.id
WHERE o.created_at >= '2026-09-01'
GROUP BY u.id;
-> Table scan on <temporary> (actual time=45.2..45.9 rows=812 loops=1)
-> Aggregate using temporary table (actual time=45.1..45.1 rows=812 loops=1)
-> Nested loop inner join (cost=2410 rows=5230) (actual time=0.09..38.7 rows=5104 loops=1)
-> Index range scan on o using orders_created_at_idx ...
(cost=580 rows=5230) (actual time=0.05..9.1 rows=5104 loops=1)
-> Single-row index lookup on u using PRIMARY (id=o.user_id)
(cost=0.25 rows=1) (actual time=0.005..0.005 rows=1 loops=5104)
Як читати:
- дерево читається зсередини назовні: найглибші вузли виконуються першими й передають рядки батьківським;
cost,rowsу перших дужках - оцінки оптимізатора;actual time=A..B- мілісекунди до першого рядка і до останнього, на одне виконання;rowsу других дужках - фактична кількість рядків на одне виконання;loops- скільки разів вузол виконувався. Повний час вузла ≈B × loops. У прикладі пошук користувача виконано 5104 рази.
На що дивитися:
- розбіжність оцінки й факту (
rows=10в оцінці,rows=200000насправді) - оптимізатор помилився через статистику й міг обрати поганий план. Лікування -ANALYZE TABLE, гістограми, переписаний запит; - вузол, де зростає час - різниця між часом вузла і його дочірніх показує, де він сам витрачає час;
- великі
loopsу вкладеному циклі - тисячі пошуків там, де міг би бути один прохід з'єднання.
EXPLAIN FORMAT=TREE (без ANALYZE) показує те саме дерево лише з оцінками - він інформативніший за табличний формат, бо видно порядок і тип з'єднань. Формат за замовчуванням можна змінити змінною explain_format.
Обережно: EXPLAIN ANALYZE справді виконує запит. Крім SELECT, він підтримує багатотабличні UPDATE і DELETE - і теж виконує їх по-справжньому, тож на продакшені аналізувати модифікації варто лише в транзакції з відкотом або на копії. Однотабличний UPDATE для аналізу зручно переписати на SELECT з тією самою умовою.