2026年6月26日

2026年6月26日

WordPressのデータベースを最適化する方法(WP-CLIで不要データを削除)

WordPressを長く運用すると、投稿のリビジョン、スパムやゴミ箱のコメント、期限切れのトランジェント(一時保存データ)などがデータベースにたまっていきます。この記事では、WP-CLI を使ってそれらの量を確認し、不要なものを削除してからテーブルを整理する手順を説明します(2026年11月時点、WordPress 7.1 と WP-CLI 2.12 で動作を確認しています)。

データの削除は元に戻せません。手順は上から順に進め、最初にバックアップを取ってから始めてください。

手順0:バックアップを取る

# WordPress のディレクトリで実行(ファイル名は任意)
cd /var/www/html
wp db export ~/backup-before-optimize.sql

エクスポートしたファイルはドキュメントルートの外に置きます。バックアップの考え方は WordPressのデータベースをバックアップする方法 も参考にしてください。

手順1:何がたまっているかを確認する

まず、どこが大きいのかを数字で見ます。

# データベース全体とテーブルごとのサイズ
wp db size --human-readable
wp db size --tables --format=table

# テーブル名の接頭辞(wp_ 以外の場合があるので確認しておく)
wp db prefix

# 大きいテーブル順に、データ・索引・未使用領域(MB)を表示
wp db query "SELECT table_name,
    ROUND(data_length/1024/1024, 2) AS data_MB,
    ROUND(index_length/1024/1024, 2) AS index_MB,
    ROUND(data_free/1024/1024, 2) AS free_MB
    FROM information_schema.tables
    WHERE table_schema = DATABASE()
    ORDER BY (data_length + index_length) DESC;"

# リビジョンの数
wp post list --post_type=revision --format=count

# スパム・ゴミ箱のコメントの数
wp comment list --status=spam --format=count
wp comment list --status=trash --format=count

# トランジェントの行数(値と有効期限の行を合わせた数)
wp option list --transients --format=count

wp option list は、--transients を付けないとトランジェントを数えません。また、Redis などの永続オブジェクトキャッシュを使っているサイトでは、トランジェントはデータベースではなくキャッシュ側に保存されます。

wp_options が大きい場合は、自動読み込み(autoload)される設定が原因のことが多いので、wp_optionsテーブルを最適化する方法 で確認してください。

手順2:不要なデータを削除する

削除の対象が0件のとき、wp post delete や wp comment delete にIDを1つも渡さないとエラーになります。次の例では、IDがあるときだけ削除を実行しています。

リビジョンを削除する

IDS=$(wp post list --post_type=revision --format=ids)
[ -n "$IDS" ] && wp post delete $IDS --force

wp post delete はリビジョンに付いたメタデータも一緒に消します。SQL で wp_posts から直接 DELETE すると、メタデータが残るうえ接頭辞の違いにも対応できないので、WP-CLI のコマンドを使います。過去の版に戻したい投稿がある場合は、先にその投稿のリビジョンだけ残すか、この手順を飛ばしてください。

スパムとゴミ箱のコメントを削除する

IDS=$(wp comment list --status=spam --format=ids)
[ -n "$IDS" ] && wp comment delete $IDS --force

IDS=$(wp comment list --status=trash --format=ids)
[ -n "$IDS" ] && wp comment delete $IDS --force

期限切れのトランジェントを削除する

wp transient delete --expired

# すべてのトランジェントを消す場合(キャッシュが作り直されるまで一時的に遅くなることがある)
# wp transient delete --all

投稿が存在しないメタデータ(孤立データ)を削除する

プラグインの削除などで、親の投稿が無いのに postmeta の行だけ残ることがあります。件数を数えてから削除します。

P=$(wp db prefix)

# 件数を確認
wp db query "SELECT COUNT(*) FROM ${P}postmeta pm
    LEFT JOIN ${P}posts p ON pm.post_id = p.ID
    WHERE p.ID IS NULL;"

# 削除
wp db query "DELETE pm FROM ${P}postmeta pm
    LEFT JOIN ${P}posts p ON pm.post_id = p.ID
    WHERE p.ID IS NULL;"

# コメントのメタデータも同様に
wp db query "DELETE cm FROM ${P}commentmeta cm
    LEFT JOIN ${P}comments c ON cm.comment_id = c.comment_ID
    WHERE c.comment_ID IS NULL;"

手順3:テーブルを最適化する(OPTIMIZE TABLE)

wp db optimize

wp db optimize は、データベースの全テーブルに対して mysqlcheck --optimize(MariaDB では mariadb-check)を実行します。InnoDB のテーブルでは、次のような表示が出ますが正常です。

wp.wp_posts
note     : Table does not support optimize, doing recreate + analyze instead
status   : OK

MySQL の公式マニュアルによると、InnoDB の OPTIMIZE TABLE はテーブルを作り直して索引の統計を更新し、未使用の領域を整理する処理です。通常の InnoDB テーブルではオンラインDDLで行われ、排他ロックは開始時と終了時の短時間だけです(FULLTEXT 索引を持つテーブルは例外で、処理中はロックされます)。一方で、テーブルを作り直すため一時的にディスク領域を使います。

効果が出やすいのは、大量の行を削除した直後です。InnoDB はもともとページに余白を残して使うので、削除をしていないテーブルを定期的に最適化しても、速度はほとんど変わりません。アクセスの少ない時間帯に、手順2の後に1回実行すれば十分です。

phpMyAdmin を使う場合は、データベースのテーブル一覧で対象のテーブルにチェックを入れ、一括操作のメニューから最適化を選びます。

手順4:たまりにくくする

リビジョンの保存数を制限する

wp-config.php に WP_POST_REVISIONS を書くと、投稿ごとに残すリビジョンの数を決められます。functions.php ではなく、wp-config.php の「編集が必要なのはここまでです」(英語版では That's all, stop editing!)の行より上に書きます。

<?php
// wp-config.php の「編集が必要なのはここまでです」の行より上に書く
// 投稿ごとに残すリビジョンの数(true = 無制限、false または 0 = 保存しない)
define( 'WP_POST_REVISIONS', 5 );

WP-CLI で書き込むこともできます。

wp config set WP_POST_REVISIONS 5 --raw

この設定はすでにあるリビジョンを一度に消すものではありません。その投稿を次に保存したときに、上限を超えた古いリビジョンから削除されます。

自動保存(AUTOSAVE_INTERVAL、既定60秒)は、投稿ごと・ユーザーごとに1件を上書きする仕組みなので、間隔を延ばしても行数はほとんど減りません。この定数も functions.php に書くと読み込みが間に合わず効きません。

期限切れトランジェントは WordPress が毎日消している

WordPress 本体は、管理画面が開かれたときに delete_expired_transients という処理を1日1回の予定で登録し、期限切れのトランジェントを削除しています。登録されているかは次のコマンドで確認できます。

wp cron event list --fields=hook,next_run_relative,recurrence | grep delete_expired_transients

WP-Cron が動いていないサイトでは、この削除も実行されません。サーバーの cron から WP-Cron を動かす方法は WP-CLIでcronを実行する方法 を参照してください。

注意点

  • 削除の前にバックアップを取り、作業はアクセスの少ない時間帯に行います。
  • wp db query の DELETE は確認なしで実行されます。先に SELECT COUNT(*) で件数を確かめてから実行してください。
  • WooCommerce など独自のテーブルを持つプラグインのデータは、プラグインの機能で整理します。直接 SQL で消すと整合性が崩れることがあります。

関連記事

お気軽にご相談ください

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