MAATRIX / Блог / MySQL: медленные запросы — причины и решение

MySQL: медленные запросы — причины и решение

MySQL: медленные запросы — причины и решение

MAATRIX

Сайт тормозит, страницы грузятся секундами, и корень часто один: MySQL медленные запросы. База — самое частое узкое место веб-приложения, и почти всегда дело в отсутствии индексов или неоптимальных запросах, а не в слабом сервере. Хорошая новость: медленные запросы легко найти и, как правило, ускорить в разы. Разберём, как поймать виновников и что с ними делать.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Первое действие: включите лог медленных запросов

Прежде чем что-то оптимизировать, найдите, какие именно запросы тормозят. MySQL умеет сам записывать их в отдельный лог. Включите его и задайте порог, например 1 секунду:

SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';

Теперь все запросы дольше секунды попадут в лог с текстом запроса и временем выполнения. Через некоторое время под реальной нагрузкой посмотрите, что накопилось. Для удобного разбора есть утилита mysqldumpslow, которая группирует похожие запросы и показывает самые тяжёлые. Это единственно верный путь: оптимизировать нужно не наугад, а конкретные запросы, которые реально тормозят. Часто выясняется, что 90% проблем создают два-три запроса — их и надо чинить в первую очередь.

Причина 1: отсутствие индексов

Самая частая причина медленных запросов — отсутствие индекса на колонках, по которым идёт поиск или соединение. Без индекса MySQL перебирает всю таблицу целиком (full table scan), и на больших данных это катастрофа. Найдите такие запросы через EXPLAIN, который показывает план выполнения:

EXPLAIN SELECT * FROM orders WHERE user_id = 123;

Если в колонке type стоит ALL, а key пустой — индекс не используется, идёт полный перебор. Добавьте индекс на колонку из условия:

CREATE INDEX idx_orders_user ON orders(user_id);

После этого тот же запрос обычно ускоряется в десятки и сотни раз. Индексируйте колонки, которые часто встречаются в WHERE, JOIN и ORDER BY. Не создавайте индексы бездумно на всё подряд — каждый индекс замедляет запись и занимает место, — но на реально используемых в фильтрах колонках они обязательны. Это самый мощный и дешёвый способ ускорить базу.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США и РФ. Оплата картой РФ и по СБП.

Арендовать VPS под базу

Причина 2: неоптимальные запросы

Иногда индекс есть, но запрос написан так, что им нельзя воспользоваться. Классика — функция или вычисление над индексированной колонкой в условии: WHERE DATE(created_at) = '2026-01-01' не даст использовать индекс на created_at, потому что MySQL применяет функцию к каждой строке. Перепишите условие на диапазон, чтобы индекс заработал:

SELECT * FROM logs WHERE created_at >= '2026-01-01' AND created_at < '2026-01-02';

Другие частые проблемы — SELECT * вместо нужных колонок, запросы, тянущие тысячи строк туда, где нужна пара, LIKE '%текст%' с ведущим процентом (индекс не работает), запросы в цикле вместо одного с JOIN. Смотрите на EXPLAIN каждого тяжёлого запроса и переписывайте так, чтобы база читала минимум данных. Часто переписанный запрос ускоряется сильнее, чем любой апгрейд железа: правильная работа с данными важнее сырой мощности сервера.

Причина 3: маленький буфер InnoDB

Если запросы оптимизированы и индексы есть, но база всё равно упирается в диск, дело может быть в размере буферного пула InnoDB. innodb_buffer_pool_size — это память, где InnoDB держит данные и индексы; если он мал, база постоянно читает с диска вместо памяти. На выделенном под базу сервере под буфер отдают значительную часть RAM (ориентир — до 60–70% от доступной памяти):

[mysqld]
innodb_buffer_pool_size = 2G

Проверьте текущее значение через SHOW VARIABLES LIKE 'innodb_buffer_pool_size'; и увеличьте, если оно неоправданно мало (дефолт часто всего 128 МБ). После правки перезапустите MySQL. Достаточный буфер позволяет держать горячие данные в памяти, и диск перестаёт быть узким местом. Это одна из самых результативных настроек производительности MySQL, о которой часто забывают, оставляя дефолт.

Причина 4: блокировки и конкуренция

Медленные запросы бывают не из-за самого запроса, а из-за ожидания блокировок: одна долгая транзакция держит строки, а остальные ждут. Внешне запрос «висит», хотя сам по себе лёгкий. Посмотрите, что происходит в базе прямо сейчас:

SHOW PROCESSLIST;

Если видите запросы в состоянии Waiting for lock или долгие транзакции — источник проблемы в блокировках. Причины — длинные транзакции, которые долго не коммитятся, отсутствие индексов (блокируется больше строк, чем нужно), неудачный порядок операций. Решение — делать транзакции короткими, коммитить вовремя, добавлять индексы (чтобы блокировались точечные строки, а не диапазоны), выносить тяжёлые операции из горячих транзакций. Под высокой конкуренцией это частая и неочевидная причина «медленных» запросов.

Как измерить эффект оптимизации

После каждой правки важно убедиться, что стало лучше, а не хуже. Замеряйте время выполнения конкретного запроса до и после:

SELECT SQL_NO_CACHE ... ;

Сравнивайте EXPLAIN до и после добавления индекса: должен смениться type с ALL на ref или range, а число просматриваемых строк — резко упасть. Следите за логом медленных запросов: после оптимизации тяжёлые запросы должны исчезнуть из него или стать быстрыми. Такой контроль не даёт заниматься мнимой оптимизацией и показывает реальный результат. Оптимизация базы — это цикл: нашли медленный запрос по логу, разобрали через EXPLAIN, исправили, замерили эффект, перешли к следующему.

Профилактика: держим базу быстрой

Чтобы медленные запросы не накапливались, встройте работу с производительностью в рутину. Держите включённым лог медленных запросов и периодически его просматривайте — так вы ловите деградацию до того, как она станет заметна пользователям. Индексируйте колонки под реальные фильтры при проектировании таблиц, а не после того, как всё легло. Выделяйте InnoDB достаточный буфер под объём горячих данных.

По мере роста данных пересматривайте индексы и запросы: то, что летало на тысяче строк, может тормозить на миллионе. Выносите тяжёлую аналитику из транзакционной базы, кэшируйте частые результаты. И честно оценивайте ресурсы: если база оптимизирована, а данных стало действительно много, дополнительная память под буфер и быстрый NVMe-диск дают ощутимый прирост. Но начинать всегда стоит с запросов и индексов — там кроется большая часть выигрыша.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США и РФ. Оплата картой РФ и по СБП.

Арендовать VPS под базу

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Частые вопросы

Как найти медленные запросы в MySQL?

Включите slow query log с порогом long_query_time, дайте базе поработать под нагрузкой и разберите накопленное, удобно через mysqldumpslow. Обычно проблему создают всего несколько запросов.

Почему запрос медленный, если индекс есть?

Часто индекс не используется: функция над колонкой в WHERE, ведущий % в LIKE, неподходящий порядок колонок в составном индексе. Смотрите EXPLAIN — он покажет, применяется ли индекс.

Насколько увеличивать innodb_buffer_pool_size?

На выделенном под базу сервере ориентир — до 60–70% доступной RAM. Дефолт часто всего 128 МБ, что мало; увеличение буфера держит горячие данные в памяти и снимает нагрузку с диска.

Как оплатить более мощный сервер из России?

В MAATRIX — картой российского банка, через СБП, криптовалютой или токеном MAAT. Иностранная карта не нужна.

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.