2026年7月15日

2026年7月15日

WordPressのwp_postsテーブルを最適化する方法

はじめに

wp_postsテーブルはWordPressで最も大きくなりやすいテーブルです。投稿リビジョン・自動保存・削除済みの下書きが蓄積することで数十万行になることがあります。定期的な整理でクエリパフォーマンスを改善できます。

症状・原因

  • 記事一覧や検索の表示が遅い
  • wp_postsテーブルが数百MBになっている
  • 投稿ページの保存に時間がかかる
  • リビジョンが1記事あたり数十件蓄積している

解決手順

ステップ1:wp_posts テーブルの内訳を把握する

-- 投稿タイプ別・ステータス別の件数とサイズ
SELECT
    post_type,
    post_status,
    COUNT(*) AS count,
    ROUND(SUM(LENGTH(post_content)) / 1024 / 1024, 2) AS content_MB
FROM wp_posts
GROUP BY post_type, post_status
ORDER BY content_MB DESC;

-- リビジョンの件数・サイズ
SELECT COUNT(*) AS revision_count,
    ROUND(SUM(LENGTH(post_content)) / 1024 / 1024, 2) AS revision_MB
FROM wp_posts WHERE post_type = 'revision';

-- 投稿ごとのリビジョン数(多い順)
SELECT post_parent, COUNT(*) AS revision_count
FROM wp_posts
WHERE post_type = 'revision'
GROUP BY post_parent
ORDER BY revision_count DESC
LIMIT 20;

ステップ2:リビジョンと自動保存を削除する

# WP-CLI でリビジョンを削除
# リビジョン数を確認
wp post list --post_type=revision --format=count

# 全リビジョンを削除
wp post delete \
    $(wp post list --post_type=revision --field=ID --format=ids) \
    --force --quiet

# SQL で直接削除(件数が多い場合)
wp db query "DELETE FROM wp_posts WHERE post_type = 'revision';"

# 自動保存(autosave)を削除
wp db query "DELETE FROM wp_posts
WHERE post_type = 'revision'
  AND post_name LIKE '%-autosave-v1';"

# ゴミ箱の投稿を削除
wp post delete \
    $(wp post list --post_status=trash --field=ID --format=ids) \
    --force --quiet

# 削除後に孤立したポストメタも削除
wp db query "DELETE pm FROM wp_postmeta pm
LEFT JOIN wp_posts p ON pm.post_id = p.ID
WHERE p.ID IS NULL;"

ステップ3:リビジョンの自動制限を設定する

// wp-config.php: リビジョン保存数を制限

// 最新3件のリビジョンのみ保持
define('WP_POST_REVISIONS', 3);

// リビジョンを完全に無効化(注意:履歴が残らない)
// define('WP_POST_REVISIONS', false);

// 自動保存の間隔を延長(デフォルト60秒)
define('AUTOSAVE_INTERVAL', 300); // 5分

// functions.php: 投稿タイプごとにリビジョン数を制限
add_filter('wp_revisions_to_keep', function(int $num, WP_Post $post): int {
    // ページは5件、投稿は3件
    if ($post->post_type === 'page') return 5;
    if ($post->post_type === 'post') return 3;
    // カスタム投稿はリビジョン不要
    return 0;
}, 10, 2);

ステップ4:wp_posts のインデックスを最適化する

-- 現在のインデックスを確認
SHOW INDEX FROM wp_posts;

-- テーブルの状態確認
ANALYZE TABLE wp_posts;

-- テーブル再構築(フラグメンテーション解消)
OPTIMIZE TABLE wp_posts;
OPTIMIZE TABLE wp_postmeta;

-- post_type + post_status の複合インデックスがなければ追加
-- (WordPressデフォルトには含まれているが確認)
SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema = DATABASE()
  AND table_name = 'wp_posts'
  AND index_name = 'type_status_date';

-- カスタム投稿タイプのクエリが遅い場合(カスタムインデックス追加)
-- ※ 本番環境ではメンテナンスモードで実行
ALTER TABLE wp_posts
ADD INDEX IF NOT EXISTS custom_type_status (post_type, post_status, post_date);

ステップ5:定期的な自動クリーンアップを設定する

// functions.php: 週次で古いリビジョンを自動削除

add_action('weekly_posts_cleanup', 'cleanup_old_revisions');

function cleanup_old_revisions(): void {
    global $wpdb;

    // 30日以上前のリビジョンを削除
    $deleted = $wpdb->query(
        "DELETE FROM {$wpdb->posts}
         WHERE post_type = 'revision'
           AND post_modified < DATE_SUB(NOW(), INTERVAL 30 DAY)"
    );

    // 各投稿の最新3件以外のリビジョンを削除
    $posts = $wpdb->get_col(
        "SELECT DISTINCT post_parent FROM {$wpdb->posts}
         WHERE post_type = 'revision' AND post_parent > 0"
    );

    foreach ($posts as $post_id) {
        $old_revisions = $wpdb->get_col($wpdb->prepare(
            "SELECT ID FROM {$wpdb->posts}
             WHERE post_type = 'revision' AND post_parent = %d
             ORDER BY post_modified DESC
             LIMIT 999 OFFSET 3",
            $post_id
        ));
        if ($old_revisions) {
            $ids = implode(',', array_map('intval', $old_revisions));
            $wpdb->query("DELETE FROM {$wpdb->posts} WHERE ID IN ($ids)");
        }
    }

    // 孤立メタデータを削除
    $wpdb->query(
        "DELETE pm FROM {$wpdb->postmeta} pm
         LEFT JOIN {$wpdb->posts} p ON pm.post_id = p.ID
         WHERE p.ID IS NULL"
    );

    error_log("[WP Posts Cleanup] Deleted revisions and orphaned meta");
}

if (!wp_next_scheduled('weekly_posts_cleanup')) {
    wp_schedule_event(time(), 'weekly', 'weekly_posts_cleanup');
}

注意事項

  • リビジョンを削除すると過去の編集履歴が失われます。重要なコンテンツがある場合は削除前にバックアップを取得してください
  • OPTIMIZE TABLE wp_postsは実行中にテーブルがロックされます。アクセスの少ない時間帯に実行してください
  • WP_POST_REVISIONSfalseに設定するとリビジョンが一切作成されなくなります。編集ミスを元に戻せなくなるため、3程度に制限することを推奨します

まとめ

wp_posts最適化は①post_type, post_status別の件数・サイズ確認でリビジョンの肥大化を定量把握、②wp post delete --forceまたはSQLで全リビジョン・自動保存・ゴミ箱を削除し孤立メタも合わせて削除、③WP_POST_REVISIONS=3wp_revisions_to_keepフィルターで投稿タイプ別上限を設定、④OPTIMIZE TABLEでフラグメンテーションを解消、⑤wp_schedule_eventで30日超リビジョンの週次自動削除と孤立メタ削除を実装します。

お気軽にご相談ください

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