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の自動バックアップ設定

お気軽にご相談ください

お見積りへ お問い合わせへ
▲