Скорость сайта

База WordPress разбухла: autoload в wp_options и мусор от плагинов

Как найти в wp_options автозагружаемые записи на мегабайты, почистить транзиенты и ревизии, и на сколько это ускорит сайт.

обновлено 8 минут чтения 2 Дмитрий Акиндинов
Содержание
  1. Что такое autoload и почему одна запись на 3 МБ грузится на каждой странице
  2. SQL-запрос, который показывает виновников по размеру
  3. Кто это оставляет: типичные источники
  4. Ревизии, транзиенты, спам и осиротевшие таблицы
  5. Безопасная чистка: бэкап, отключение автозагрузки, удаление
  6. Чек-лист перед тем как трогать базу
  7. Что это даёт в цифрах и когда дело не в базе
  8. Частые вопросы

В WordPress есть таблица настроек, часть которой грузится целиком на каждом запросе. У здорового сайта это 1-2 МБ, а на запущенном встречаются отдельные записи по 2-5 МБ и суммарный объём за 10. Каждая страница тащит их вместе с собой, включая страницы для ботов.

Сайт на WordPress тормозит, кэш стоит, CDN подключен, а TTFB всё равно за секунду. Причина в половине таких случаев не в PHP и не в хостинге, а в таблице wp_options, которая за пару лет работы плагинов и виджетов раздулась до неприличных размеров и грузится целиком на каждый запрос. Эта статья для тех, кто администрирует сайт на WordPress и хочет понять, где искать раздутую базу, как её безопасно почистить и сколько это реально даёт в цифрах, а не на словах «ускорит сайт».

Цилиндр базы данных, переполненный блоками данных

Что такое autoload и почему одна запись на 3 МБ грузится на каждой странице

Таблица wp_options хранит настройки: адрес сайта, активные плагины, тему, виджеты, опции почти любого плагина, который вы когда-либо ставили. У каждой записи в этой таблице есть колонка autoload, значение yes или no.

Записи с autoload = yes WordPress подгружает одним запросом в самом начале обработки любой страницы, до того как решит, какой шаблон вообще рисовать. Логика в этом есть: часть настроек нужна буквально везде, и проще один раз вытащить их все, чем гонять по отдельному запросу на каждую. Проблема начинается, когда плагины пишут в autoload то, что там быть не должно: закэшированный ответ внешнего API, список всех страниц сайта, служебный массив с логами обновлений, дамп настроек слайдера на 40 слайдов.

WordPress десять лет назад сам предупреждал разработчиков плагинов не класть в autoload что-то тяжелее пары килобайт. Часть авторов плагинов это правило не читала никогда. В итоге на живом сайте нередко находится одна-две записи по 2-5 МБ, которые тянутся при каждом обращении к сайту, включая запросы от ботов, REST API и admin-ajax.

SQL-запрос, который показывает виновников по размеру

Не нужно перебирать записи руками. Один запрос через phpMyAdmin, Adminer или консольный wp db query показывает топ автозагружаемых опций, отсортированный по весу.

SELECT option_name, LENGTH(option_value) AS size_bytes
FROM wp_options
WHERE autoload = 'yes'
ORDER BY size_bytes DESC
LIMIT 20;

Если под рукой WP-CLI, то же самое делается без похода в SQL-клиент:

wp option list --autoload=yes --format=table --fields=option_name,size_bytes 
  --orderby=size --order=desc | head -20

И сразу общий вес всего autoload одним числом:

SELECT ROUND(SUM(LENGTH(option_value)) / 1024 / 1024, 2) AS total_mb
FROM wp_options
WHERE autoload = 'yes';

На здоровом сайте средних размеров суммарный autoload держится в пределах 1-2 МБ. Я регулярно вижу цифры за 10 МБ, а рекорд в моей практике был чуть больше 40 МБ на сайте с историей в семь лет и десятком сменившихся конструкторов страниц. Это значит, что при каждом обращении к сайту MySQL вытаскивает и передаёт PHP-процессу 40 МБ данных, прежде чем страница вообще начнёт формироваться.

Кто это оставляет: типичные источники

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

ИсточникЧто происходит
Удалённые плагиныНастройки остаются в базе даже после деактивации и удаления плагина через админку
Слайдеры и билдеры страницКаждый слайд, блок или шаблон сохраняется как часть одной большой опции
Кэш внешних APIПлагины гео-виджетов, курсов валют, погоды кладут ответ API в autoload вместо transient с TTL
Статистика и логи в базеНекоторые плагины безопасности и SEO пишут историю событий прямо в wp_options
Брошенные настройки после смены темыКонструктор темы (Elementor, Divi, WPBakery) хранит структуру каждой собранной страницы
Тестовые данные разработчиковЗабытые дебаг-опции, дампы для отладки, которые никто не убрал после запуска

Отдельная категория — плагины, которые правильно помечают опцию как autoload = no, но всё равно исполняют лишний SQL-запрос на каждой странице через собственный код, а не через штатный API опций. Это уже не лечится чисткой базы, там нужно смотреть Query Monitor и разбираться с конкретным плагином отдельно.

Ревизии, транзиенты, спам и осиротевшие таблицы

Autoload обычно самый заметный виновник, но не единственный источник разбухания базы.

Ревизии записей. WordPress по умолчанию сохраняет неограниченное число версий каждой статьи и страницы при каждом автосохранении. На сайте, где статьи правились годами, таблица wp_posts может на треть состоять из старых ревизий, каждая с полным текстом статьи целиком. Отключить дальнейшее накопление можно строкой в wp-config.php:

define('WP_POST_REVISIONS', 5);

Она ограничивает число хранимых ревизий пятью на запись, но не удаляет уже накопленные, для этого нужна отдельная чистка SQL-запросом или через WP-CLI (wp post delete $(wp post list --post_type='revision' --format=ids)).

Транзиенты. Это временный кэш с истёкшим сроком жизни, который штатно должен удаляться сам, но при ручном обновлении времени на сервере, смене таймзоны или прерванном крон-задании транзиенты копятся и не чистятся. Проверяются так:

SELECT COUNT(*) FROM wp_options WHERE option_name LIKE '_transient_%';

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

Спам-комментарии. Если Akismet или другой антиспам держит комментарии в статусе «спам» вместо удаления, за годы работы сайта таблица wp_comments может распухнуть на десятки тысяч строк, которые никому не нужны и никогда не будут опубликованы.

Осиротевшие таблицы. После удаления некоторых плагинов (особенно форумных движков, каталогов товаров, старых версий кэш-плагинов) в базе остаются собственные таблицы плагина, к которым WordPress больше не обращается вообще. Список всех таблиц сайта:

SHOW TABLES;

Сверьте список с фактически используемыми плагинами: таблицы вроде wp_wpforms_entries от давно удалённого WPForms или wp_ai1wm_... от старого мигратора можно смело выносить в архив и удалять, если плагином давно не пользуетесь.

Безопасная чистка: бэкап, отключение автозагрузки, удаление

Перед любой правкой базы обязателен свежий бэкап, причём именно базы, а не только файлов. Если своего процесса нет, порядок действий описан в статье про резервные копии WordPress без платных плагинов, а сколько версий бэкапов вообще стоит хранить, разобрано отдельно в материале сколько хранить бэкапы сайта.

Дальше порядок такой.

  1. Снять дамп базы (wp db export или через панель хостинга).
  2. Выполнить запрос топ-20 автозагружаемых опций по размеру (см. выше) и выписать имена.
  3. Для каждой найденной опции проверить, к какому плагину она относится (по префиксу имени: elementor_, wc_, yoast_ и так далее).
  4. Если плагин активен и опция ему реально нужна каждый раз, но лишний вес по нему не критичен, оставить.
  5. Если плагин удалён или опция это явно кэш/лог/дебаг-данные, переключить autoload на no вместо немедленного удаления, чтобы не сломать что-то, что читает эту опцию редко, но использует:
UPDATE wp_options SET autoload = 'no' WHERE option_name = 'название_опции';
  1. Через неделю без ошибок на сайте и в error_log удалить неиспользуемые записи насовсем:
DELETE FROM wp_options WHERE option_name = 'название_опции';
  1. Проверить сайт полностью: главную, карточку товара или услуги, форму, админку. Не только визуально, но и по логам (tail -f error_log во время прогона).

Отдельно транзиенты можно почистить одной командой, не разбирая каждую запись вручную:

wp transient delete --expired

Она трогает только просроченные транзиенты и безопасна на любом сайте.

Чек-лист перед тем как трогать базу

Прежде чем садиться за SQL-запросы, стоит быстро понять, актуальна ли вообще эта проблема для конкретного сайта. Пять минут на проверку экономят часы на чистку того, что чистить не требовалось.

  • [ ] Суммарный вес autoload больше 2-3 МБ (запрос из первого раздела статьи)
  • [ ] В топ-20 автозагружаемых опций есть записи от плагинов, которых сейчас нет в списке активных
  • [ ] Число ревизий записей больше, чем число самих записей (SELECT COUNT(*) FROM wp_posts WHERE post_type = 'revision')
  • [ ] Просроченных транзиентов больше нескольких тысяч
  • [ ] В базе есть таблицы, чьи префиксы не соответствуют ни одному установленному сейчас плагину
  • [ ] Свежий бэкап базы снят и проверен на возможность восстановления

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

Что это даёт в цифрах и когда дело не в базе

На практике эффект зависит от того, насколько раздута база и насколько сайт вообще упирался именно в это. Реальные случаи из моей работы: сайт услуг с autoload в 18 МБ после чистки до 900 КБ дал падение TTFB с 640 мс до 280 мс на том же shared-хостинге без единой смены настроек PHP. Интернет-магазин с 30 МБ автозагрузки (в основном забытый кэш курсов валют, обновлявшийся раз в час, но хранившийся полным дампом за весь год) после чистки ускорил админку заметнее, чем фронт: там разница была почти двукратной именно на страницах со списками товаров.

Но чистка базы не панацея. Если TTFB и так укладывается в 200-300 мс, а узкое место в тяжёлых изображениях, отсутствии кэша страниц или медленном внешнем API в footer, autoload погоды не сделает. Проверить, где реально теряется время, помогает Query Monitor: если после чистки базы SQL-запросов на страницу стало значительно меньше, а время рендера почти не изменилось, значит проблема не в базе, а где-то ещё, и стоит смотреть в сторону конкретных плагинов, как описано в материале про то, как WordPress тормозит после трёх лет работы.

Итоговая проверка простая: замерьте TTFB до чистки и через сутки после (не сразу, чтобы кэш успел прогреться заново), сравните с реальными цифрами, а не на глазок. Если разница есть, но небольшая, следующий шаг обычно гигиена кэширования на уровне сервера, а не дальнейшее копание в базе. Если после всех замеров картина не складывается и непонятно, куда уходит время генерации страницы, разумнее один раз показать конкретные цифры специалисту через форму на главной, чем гонять чистку базы вслепую ещё несколько раз подряд.

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

Почему база WordPress тормозит сайт

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

Какой размер автозагрузки нормальный

1-2 МБ у сайта средних размеров. Всё, что заметно больше, стоит разбирать. Отдельная запись на несколько мегабайт это почти всегда чей-то забытый кэш.

Что ещё раздувает базу

Ревизии записей, временные значения, спам в комментариях и таблицы удалённых плагинов, которые никто не убрал. По отдельности мелочь, вместе гигабайты.

Как чистить безопасно

Сначала бэкап. Потом смотреть, какие записи самые тяжёлые, и разбираться, чьи они. Автозагрузку у ненужных отключают, сами записи удаляют только тогда, когда понятно, что это и откуда.

Передайте техническую часть в надёжные руки.

Слежу за хостингом, бэкапами и обновлениями. Когда что-то пойдёт не так – звоните мне, не своему программисту, не в спортзал и не маме.

Короткие вопросы по теме

Все вопросы по теме "Скорость сайта"

Заявка

Обсудим задачу

Напишите имя и телефон, выберите удобный канал. Перезвоню или напишу в течение часа в рабочее время.

Куда удобнее ответить?