Каждый вебмастер хотя бы раз получал тревожное уведомление от техподдержки хостинга: «Ваш аккаунт превышает допустимые лимиты нагрузки на сервер баз данных MySQL (CPU / IOPS)». Вслед за этим сайт начинает открываться с мучительной задержкой в 5–10 секунд, а на экране периодически всплывает ошибка 508 Resource Limit Reached или Error Establishing a Database Connection.
В 90% случаев виноват вовсе не хостинг, а неэффективные, неоптимизированные SQL-запросы, выполняющие полное сканирование таблиц (Full Table Scan) на миллионы строк. В этом руководстве инженеры TopHosting разберут 7 практических шагов по наведению порядка в базе данных MySQL / MariaDB.
Шаг 1. Включаем журнал медленных запросов (Slow Query Log)
Невозможно лечить болезнь, не зная симптомов. Slow Query Log — встроенный инструмент MySQL, который протоколирует все запросы, выполняющиеся дольше заданного порога времени (например, дольше 1 секунды).
Параметры для файла конфигурации my.cnf (на VPS) или через phpMyAdmin:
slow_query_log = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 1
log_queries_not_using_indexes = 1
Если у вас виртуальный хостинг, попросите службу поддержки предоставить выгрузку медленных запросов вашего пользователя за последние сутки — большинство белорусских провайдеров формируют такие отчеты автоматически.
Шаг 2. Анализ запросов через EXPLAIN
Возьмите самый частый тяжелый запрос из журнала и выполните его в phpMyAdmin, добавив в начало команду EXPLAIN:
EXPLAIN SELECT * FROM wp_posts WHERE post_status = 'publish' AND post_type = 'product' ORDER BY post_date DESC;
Обратите внимание на три ключевые колонки:
- type: Если вы видите значение
ALL— это катастрофа! Сервер сканирует каждую строчку таблицы целиком. Идеальные значения —ref,eq_refилиrange. - rows: Примерное число строк, которые MySQL приходится перебирать для формирования ответа. Если в таблице 100 000 товаров, а в колонке rows стоит 98 000 — запрос не использует индексы.
- Extra: Наличие надписи
Using filesortилиUsing temporaryозначает, что сервер создает временную таблицу на диске для сортировки результатов, моментально сжигая лимиты IOPS хостинга.
3. Шаг 3. Добавление составных индексов (Indexes)
Индекс в базе данных работает точно так же, как алфавитный указатель в конце энциклопедии: вместо чтения всей книги сервер мгновенно переходит к нужной странице.
Если запрос фильтрует данные по нескольким колонкам (например, статус заказа и дата), одиночные индексы малоэффективны — необходим составной (композитный) индекс:
ALTER TABLE oc_order ADD INDEX idx_status_date (order_status_id, date_added);
Правило порядка колонок: Сначала в индекс помещаются колонки с точным совпадением (=), а затем колонки для диапазонных условий (>, <, BETWEEN) или сортировки (ORDER BY).
4. Шаг 4. Расчистка таблицы wp_options (для сайтов на WordPress)
Главный «убийца» производительности в WordPress — таблица wp_options. При каждом открытии любой страницы сайта WordPress делает запрос:
SELECT option_name, option_value FROM wp_options WHERE autoload = 'yes';
За годы работы удаленные плагины оставляют в этой таблице мегабайты забытых настроек, кэша транзиентов и логов. Если объем автозагружаемых данных превышает 800 КБ — сайт начнет тормозить.
Очистка просроченных временных данных (Transients):
DELETE FROM wp_options WHERE option_name LIKE ('_transient_%');
DELETE FROM wp_options WHERE option_name LIKE ('_site_transient_%');
5. Шаг 5. Чистка логов, сессий и корзин в интернет-магазинах
| CMS | Проблемная таблица | Что делать |
|---|---|---|
| WooCommerce | wp_woocommerce_sessions, actionscheduler_actions |
Очистить сессии гостей старше 7 дней, удалить выполненные задачи Action Scheduler. |
| OpenCart | oc_customer_online, oc_cart |
Очистить устаревшие корзины брошенных сессий ботов и журнал активности покупателей. |
| 1С-Битрикс | b_event_log, b_stat_hit |
Сократить срок хранения статистики и журнала событий с 30 до 3–7 дней. |
6. Шаг 6. Перевод таблиц на движок InnoDB
Если ваш сайт создавался давно, в базе могут оставаться таблицы устаревшего формата MyISAM. Главный недостаток MyISAM — блокировка всей таблицы целиком (Table-level locking) при любой записи. Если один покупатель оформляет заказ, все остальные пользователи ждут в очереди.
Современный движок InnoDB использует построчную блокировку (Row-level locking) и полностью поддерживает транзакции (ACID). Конвертировать таблицы можно в phpMyAdmin командой:
ALTER TABLE имя_таблицы ENGINE = InnoDB;
7. Шаг 7. Кэширование запросов в оперативной памяти (Redis / Memcached)
Самый быстрый SQL-запрос — это запрос, который вообще не пришлось отправлять в базу данных! Настроив хранилище Redis в качестве объектного кэша (Object Cache), результаты частых запросов будут отдаваться прямо из RAM со скоростью 1–2 мс.
Подробную инструкцию по включению серверного кэша читайте в нашей статье: «Как ускорить сайт с помощью Redis и OPcache на хостинге».