2026年11月1日
2026年11月1日
WordPressデータベースの定期最適化方法【自動クリーンアップ・WP-CLI】
はじめに
WordPressを長期間使い続けると、データベースに不要なデータが蓄積されます。投稿リビジョン・スパムコメント・孤立したメタデータ・期限切れTransientなどが積み重なり、データベースのサイズが膨れ上がりクエリが遅くなります。
症状・原因
- サイトが以前より遅くなった(DBサイズが数GB以上)
wp_postsテーブルにリビジョンが数万件以上あるwp_optionsテーブルのautoloadデータが1MB以上あるwp_postmetaに孤立したメタデータが大量にある
解決手順
ステップ1:不要データをWP-CLIで確認・削除する
# リビジョン数を確認
wp post list --post_type=revision --format=count
# 古いリビジョンを削除(直近3件を保持)
wp post delete $(wp post list --post_type=revision --format=ids) --force
# 期限切れTransientを削除
wp transient delete --expired
# スパムコメントを削除
wp comment delete $(wp comment list --status=spam --format=ids) --force
# ゴミ箱の投稿を削除
wp post delete $(wp post list --post_status=trash --format=ids) --force
# 孤立したpostmetaを削除(WooCommerceなど大型プラグイン使用時)
wp eval '
global $wpdb;
$deleted = $wpdb->query("
DELETE pm FROM wp_postmeta pm
LEFT JOIN wp_posts p ON p.ID = pm.post_id
WHERE p.ID IS NULL
");
echo "Deleted: $deleted orphaned postmeta rows\n";
'
ステップ2:リビジョン数を制限する
// wp-config.php: リビジョンを3件に制限
define('WP_POST_REVISIONS', 3);
// functions.php: リビジョンを完全無効化(サイトの規模による)
// add_filter('wp_revisions_to_keep', '__return_zero');
// リビジョン保存間隔を延長(デフォルト60秒→5分)
add_filter('wp_save_post_revision_check_for_changes', '__return_true');
define('AUTOSAVE_INTERVAL', 300); // 5分
// 投稿タイプ別にリビジョン数を制御
add_filter('wp_revisions_to_keep', function(int $num, WP_Post $post): int {
return match($post->post_type) {
'page' => 5,
'product' => 2,
default => 3,
};
}, 10, 2);
ステップ3:autoloadオプションの最適化
// autoloadが多いオプションを確認
add_action('admin_init', function(): void {
if (!current_user_can('manage_options')) return;
if (!isset($_GET['check_autoload'])) return;
global $wpdb;
$results = $wpdb->get_results("
SELECT option_name, LENGTH(option_value) AS size
FROM {$wpdb->options}
WHERE autoload = 'yes'
ORDER BY size DESC
LIMIT 20
");
foreach ($results as $row) {
error_log(sprintf(
'[Autoload] %s: %s bytes',
$row->option_name,
number_format($row->size)
));
}
});
// プラグイン由来の大きなautoloadオプションをno-autoloadに変更
function disable_autoload(string $option_name): void {
global $wpdb;
$wpdb->update(
$wpdb->options,
['autoload' => 'no'],
['option_name' => $option_name],
['%s'],
['%s']
);
}
// 例: 使っていないプラグインの残骸を修正
// disable_autoload('woocommerce_session_expiration');
ステップ4:定期自動クリーンアップを設定する
// WP-Cronで毎週自動クリーンアップ
add_action('init', function(): void {
if (!wp_next_scheduled('wp_db_weekly_cleanup')) {
wp_schedule_event(time(), 'weekly', 'wp_db_weekly_cleanup');
}
});
add_action('wp_db_weekly_cleanup', function(): void {
global $wpdb;
// 期限切れTransient削除
$wpdb->query("
DELETE FROM {$wpdb->options}
WHERE option_name LIKE '_transient_%'
AND option_name LIKE '_transient_timeout_%'
AND option_value < UNIX_TIMESTAMP()
");
// 30日以上古いゴミ箱の投稿を削除
$wpdb->query("
DELETE p, pm, tr
FROM {$wpdb->posts} p
LEFT JOIN {$wpdb->postmeta} pm ON pm.post_id = p.ID
LEFT JOIN {$wpdb->term_relationships} tr ON tr.object_id = p.ID
WHERE p.post_status = 'trash'
AND p.post_modified < DATE_SUB(NOW(), INTERVAL 30 DAY)
");
// テーブルを最適化
$wpdb->query("OPTIMIZE TABLE {$wpdb->posts}");
$wpdb->query("OPTIMIZE TABLE {$wpdb->postmeta}");
$wpdb->query("OPTIMIZE TABLE {$wpdb->options}");
error_log('[DB Cleanup] Weekly database cleanup completed: ' . date('Y-m-d H:i:s'));
});
ステップ5:テーブル最適化と確認
# MySQLでテーブルの断片化を確認
mysql -u root -p wordpress -e "
SELECT TABLE_NAME,
ROUND(DATA_LENGTH/1024/1024, 2) AS data_mb,
ROUND(DATA_FREE/1024/1024, 2) AS free_mb
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'wordpress'
ORDER BY DATA_FREE DESC;"
# WP-CLIでDBを最適化
wp db optimize
# DBサイズを確認
wp db size
# 特定テーブルのサイズ確認
wp db size --tables
# DBをエクスポートして確認
wp db export - | gzip > /tmp/db-before-optimize.sql.gz
注意事項
- バックアップ必須: 最適化前に必ずデータベースのバックアップを取得してください
- リビジョン完全無効化: コンテンツ管理の観点からリビジョン0件は推奨しません。最低3件は保持してください
OPTIMIZE TABLE: MyISAMテーブルではテーブルロックが発生します。InnoDB(推奨)ではオンラインで動作します- WooCommerce: WooCommerceの注文・顧客データは慎重に扱ってください。誤削除すると復元困難です
まとめ
データベース最適化の定期メンテナンスは「リビジョン制限・Transient削除・孤立メタ削除・OPTIMIZE TABLE」の4つが基本です。WP-Cronで毎週自動実行することで、常にデータベースを軽量に保てます。関連記事:WordPressの自動バックアップ設定