#Как проявляется проблема и где искать причину
Перед оптимизацией медленного запроса MySQL можно увидеть его план через EXPLAIN, не выполняя сам запрос, однако EXPLAIN ANALYZE действительно выполняет SELECT. На рабочей базе важно сначала получить план с минимальным риском.
| Возможная причина | Как узнать | Что делать |
|---|---|---|
| Неоптимальный доступБольшой rows и полное сканирование таблицы | type=ALL при большом объёме строк | Проверить индексы и условия |
| Ошибочная оценкаОптимизатор неверно оценивает селективность | Оценка rows не соответствует данным теста | Сравнить статистику после безопасного анализа |
#Пошаговая диагностика и устранение
- 1. Найдите именно тот SELECT, который медленныйВозьмите SQL из приложения или медленного журнала, обезличьте параметры. Зафиксируйте время выполнения, пример значений фильтров и схему базы. Не считайте одинаковыми планы запросов с радикально разными параметрами.
- 2. Проверьте роль подключенияОткройте отдельную сессию mysql с правами только на чтение. В ней выберите нужную базу и проверьте версию. При нехватке прав запросите администратору безопасный доступ к EXPLAIN.
- mysql-клиент, чтение; при DATABASE()=NULL выберите нужную схемуSQLКомандаmysql-клиент, чтение; при DATABASE()=NULL выберите нужную схему.
SELECT VERSION(), DATABASE();
- 3. Получите оценочный планВыполните EXPLAIN перед реальным SELECT. В примере используется условная таблица; замените её на свою. Смотрите type, possible_keys, key, rows и Extra.SQLКомандаПример SELECT, замените запрос на реальный; EXPLAIN не выполняет SELECT как EXPLAIN ANALYZE.
EXPLAIN SELECT id, status FROM appdb.orders WHERE customer_id = 42;
- 4. Интерпретируйте признаки сканированияtype=ALL указывает на полное сканирование, но оно не всегда плохо для маленькой таблицы. Проверьте количество строк, фильтрацию и использование составного индекса. Не делайте вывод только по наличию индекса в поле key.
- 5. Сверьте реальные индексы и объём таблицыПосмотрите SHOW INDEX и приблизительные сведения о таблице. Убедитесь, что порядок колонок составного индекса соответствует предикатам WHERE и JOIN, а статистика не слишком стара.SQLКомандаПодставьте нужную таблицу; чтение структуры.
SHOW INDEX FROM appdb.orders;
- 6. Сравните JSON-план при необходимостиДля сложных соединений EXPLAIN FORMAT=JSON показывает дерево доступа и дополнительные оценки. Формат и названия полей зависят от версии MySQL, поэтому сохраняйте версию вместе с результатом.SQLКомандаТолько пример SELECT; чтение плана.
EXPLAIN FORMAT=JSON SELECT id, status FROM appdb.orders WHERE customer_id = 42;
- 7. Измерьте фактическое время только на тестеEXPLAIN ANALYZE выполняет SELECT и может занимать ресурсы. Применяйте его в отдельной копии с сопоставимым количеством данных и безопасными параметрами, а не автоматически в рабочую нагрузку.SQLС осторожностьюТолько тестовая среда: запрос действительно исполняется.
EXPLAIN ANALYZE SELECT id, status FROM appdb.orders WHERE customer_id = 42;Команда может изменить состояние системы или её настройки. Проверьте параметры и последствия перед запуском.
- 8. Проверяйте каждое изменение сравнениемПосле возможного изменения SQL/индекса на тесте повторите EXPLAIN и измерение времени. Успех — уменьшено число обработанных строк и время выполнения без ухудшения других запросов и записи. При сомнениях возвращайте прежний план теста.
#Как проверить результат
Получен сохранённый план и подтверждённое в тесте улучшение с одинаковыми входными параметрами; рабочая база не подвергалась опасному профилированию.
#Если исправление не помогло
При запросах с побочными функциями не считайте EXPLAIN универсально безопасным: сначала оцените текст и план выполнения совместно с DBA.