У вас магазин на WooCommerce. Тысячи заказов, тонны метаданных. Вы перешли на HPOS — и вроде всё работает, но база данных весит как будто миграция не удалила старые данные. Знакомая ситуация?
Именно с этим столкнулся один из наших клиентов: после миграции на HPOS база данных выросла на 2 ГБ вместо того, чтобы сжаться. Заказы дублировались в двух системах хранения, cron-задачи тормозили, а время генерации отчётов увеличилось втрое. Проблема оказалась тривиальной — старые записи никто не почистил.
В этой статье расскажу, как привести таблицы заказов WooCommerce в порядок после миграции на HPOS, избежать типичных ошибок и вернуть магазину ту производительность, ради которой вы всё это затевали.
Что такое HPOS и зачем вообще нужна миграция
До появления HPOS WooCommerce хранила заказы в таблицах wp_posts и wp_postmeta — то есть заказы жили рядом с обычными записями блога и страницами. Каждый заказ — это пост типа shop_order, а все его данные (адрес, товары, скидки) — это метаполя.
Проблема в том, что таблица wp_postmeta растёт экспоненциально. Магазин с 50 000 заказами генерирует примерно 700 000 — 1 000 000 строк в wp_postmeta. Каждое обновление заказа добавляет новые записи, не удаляя старые. Запросы к этой таблице становятся неприлично медленными.
HPOS (High Performance Order Storage) решает эту проблему, создавая отдельные таблицы специально для заказов:
wp_wc_orders— основная информация о заказеwp_wc_orders_meta— метаданные заказаwp_wc_order_addresses— адреса доставки и оплатыwp_wc_order_operational_data— операционные данные (валюта, суммы налогов)
Результат — запросы к заказам работают в 5-10 раз быстрее на больших объёмах данных. Для магазина с десятками тысяч заказов разница ощутима сразу: отчёты генерируются за секунды вместо минут, админка перестаёт «подвисать».
Как происходит миграция и что остаётся «после»
WooCommerce предлагает два режима хранения заказов:
- Синхронизированный режим — данные записываются и в старые таблицы, и в новые
- Режим только HPOS — заказы хранятся исключительно в новых таблицах
Миграция запускается через WooCommerce → Настройки → Расширенные → Хранилище заказов. WooCommerce копирует все заказы из wp_posts/wp_postmeta в новые HPOS-таблицы. Весь процесс может занять от нескольких минут до нескольких часов — зависит от количества заказов.
И вот тут кроется главный подвох: миграция копирует данные, но не удаляет старые записи. Это сделано намеренно — на случай отката. Но если вы убедились, что всё работает корректно, старый хлам нужно убирать вручную.
Проверка целостности после миграции
Прежде чем что-то удалять, обязательно проверьте, что миграция прошла корректно. Потерять данные о заказах — это не шутки.
Сравнение количества записей
Первый шаг — убедиться, что количество заказов совпадает в обеих системах хранения.
-- Количество заказов в старой системе
SELECT COUNT(*) as old_orders
FROM wp_posts
WHERE post_type = 'shop_order'
AND post_status NOT IN ('auto-draft', 'trash');
-- Количество заказов в HPOS
SELECT COUNT(*) as new_orders
FROM wp_wc_orders;
Числа должны совпадать (или быть очень близки — небольшая разница возможна из-за черновиков и мусорных записей). Если расхождение значительное — не удаляйте старые данные, сначала разберитесь, что пошло не так.
Проверка через встроенный инструмент WooCommerce
WooCommerce имеет встроенный механизм верификации. В админке перейдите в WooCommerce → Статус → Инструменты и найдите пункт «Синхронизация HPOS». Запустите проверку — система сравнит данные в обеих таблицах и покажет расхождения.
Проверка случайных заказов
Выберите 10-20 заказов из разных периодов и проверьте их вручную: товары, суммы, адреса, статусы. Откройте несколько заказов в админке, убедитесь, что всё отображается корректно.
Очистка старых данных заказов из wp_posts и wp_postmeta
Итак, вы убедились, что миграция прошла успешно. Теперь можно приступать к очистке. Но перед этим — сделайте бэкап базы данных. Серьёзно. Это не формальность, а страховка от потери данных, восстановление которых потом обойдётся в разы дороже.
Удаление записей заказов из wp_posts
-- Сначала посмотрите, сколько записей будет удалено
SELECT COUNT(*)
FROM wp_posts
WHERE post_type IN ('shop_order', 'shop_order_refund');
-- Удаление записей заказов
DELETE FROM wp_posts
WHERE post_type IN ('shop_order', 'shop_order_refund');
Для магазина с 100 000 заказами этот запрос может выполняться несколько минут. Если таблица очень большая, лучше удалять порциями:
-- Удаление порциями по 5000 записей
DELETE FROM wp_posts
WHERE post_type IN ('shop_order', 'shop_order_refund')
LIMIT 5000;
Запускайте этот запрос повторно, пока COUNT не покажет ноль.
Удаление метаданных заказов из wp_postmeta
Метаданные — это самая «тяжёлая» часть. Именно в wp_postmeta накапливается основной мусор.
-- Удаление метаданных, связанных с заказами DELETE pm FROM wp_postmeta pm LEFT JOIN wp_posts p ON pm.post_id = p.ID WHERE p.ID IS NULL;
Этот запрос удалит все метаполя, у которых нет родительской записи в wp_posts — то есть «осиротевшие» данные. После удаления заказов из wp_posts их метаданные как раз и становятся такими осиротевшими записями.
Удаление связанных записей
Не забудьте про дополнительные данные, которые WooCommerce создаёт для заказов:
-- Удаление связей заказов с товарами в wp_term_relationships
DELETE tr
FROM wp_term_relationships tr
INNER JOIN wp_posts p ON tr.object_id = p.ID
WHERE p.post_type IN ('shop_order', 'shop_order_refund');
-- Очистка wc_order_stats (если используется аналитика)
-- Будьте осторожны: эти данные могут понадобиться для отчётов
Оптимизация HPOS-таблиц после очистки
После удаления старых данных таблицы wp_posts и wp_postmeta физически не уменьшатся — MySQL просто пометит строки как удалённые. Нужно явно попросить базу данных освободить дисковое пространство.
Оптимизация через SQL
OPTIMIZE TABLE wp_posts; OPTIMIZE TABLE wp_postmeta; OPTIMIZE TABLE wp_wc_orders; OPTIMIZE TABLE wp_wc_orders_meta; OPTIMIZE TABLE wp_wc_order_addresses; OPTIMIZE TABLE wp_wc_order_operational_data;
Время выполнения зависит от размера таблиц. Для таблицы wp_postmeta с миллионом строк оптимизация может занять 10-30 минут, на время которых таблица будет заблокирована. Лучше запускать это в период минимальной нагрузки.
Очистка транзакций WooCommerce
WooCommerce хранит логи транзакций платёжных систем, и со временем они занимают немало места. Если вы используете встроенный механизм транзакций:
-- Проверка наличия таблицы транзакций SHOW TABLES LIKE 'wc_orders_transactions'; -- Удаление старых транзакций (старше 90 дней) DELETE FROM wc_orders_transactions WHERE date_created_gmt < DATE_SUB(NOW(), INTERVAL 90 DAY); [/sql] <h3>Пересчёт индексов</h3> <p>После массовых удалений полезно обновить статистику индексов, чтобы оптимизатор запросов MySQL выбирал правильные планы выполнения:</p> [sql] ANALYZE TABLE wp_posts; ANALYZE TABLE wp_postmeta; ANALYZE TABLE wp_wc_orders; ANALYZE TABLE wp_wc_orders_meta;
Автоматическая очистка: настройка расписания
Если вы не хотите повторять всё это вручную каждые несколько месяцев, настройте автоматическую очистку. WooCommerce позволяет удалять старые заказы через хуки:
// Удаление заказов старше 2 лет (кроме завершённых и отменённых за последний год)
add_action('woocommerce_cleanup_orders', function() {
global $wpdb;
$cutoff_date = date('Y-m-d H:i:s', strtotime('-2 years'));
// Только если HPOS активен
if (wc_get_container()->get(\Automattic\WooCommerce\Utilities\OrderUtil::class)->custom_orders_table_usage_is_enabled()) {
$wpdb->query($wpdb->prepare(
"DELETE FROM {$wpdb->prefix}wc_orders
WHERE date_created_gmt < %s
AND status IN ('trash', 'cancelled', 'failed')",
$cutoff_date
));
}
}, 10, 0);
[/php]
<p>Для запуска по расписанию зарегистрируйте хук в WordPress cron:</p>
[php]
// Регистрация cron-события при активации
register_activation_hook(__FILE__, function() {
if (!wp_next_scheduled('woocommerce_cleanup_orders')) {
wp_schedule_event(time(), 'monthly', 'woocommerce_cleanup_orders');
}
});
// Очистка при деактивации
register_deactivation_hook(__FILE__, function() {
wp_clear_scheduled_hook('woocommerce_cleanup_orders');
});
Удобный вариант — создать отдельный плагин-мустюплагин (wp-content/mu-plugins/cleanup-hpos.php), тогда он не будет зависеть от активации конкретного плагина.
Типичные ошибки при очистке таблиц WooCommerce
За годы работы с WooCommerce я видел немало «интересных» подходов к оптимизации базы данных. Вот самые частые ошибки:
Удаление заказов до завершения миграции. Звучит очевидно, но бывает. Если миграция прервалась на середине, а вы уже почистили wp_posts — заказы, которые не успели попасть в HPOS, потеряны навсегда. Всегда проверяйте статус миграции.
Использование phpMyAdmin для массовых удалений. Попытка удалить 100 000 строк через веб-интерфейс phpMyAdmin обычно заканчивается тайм-аутом и повреждением данных. Используйте CLI или порционные удаления.
Игнорирование бэкапов. «Да я просто гляну, что там, потом удалю». Сделайте дамп хотя бы через mysqldump:
mysqldump -u username -p database_name wp_posts wp_postmeta > backup_before_cleanup.sql
Удаление записей с неправильным post_type. Проверьте, что в вашей таблице нет кастомных типов записей, которые могут совпадать с «shop_order». Иногда плагины создают собственные типы записей.
Какой результат вы получите
Для магазина с 50 000 заказами типичный результат после полной очистки и оптимизации:
Добавить комментарий