2026年8月21日

2026年8月21日

WordPressのデータベース肥大化を防ぐ設定|リビジョン・Transient・autoload・スパム

WordPressのデータベースは、運用を続けるうちにリビジョン、Transient(一時キャッシュ)、プラグインのオプション、スパムコメントなどで大きくなります。一度掃除しても、増える原因を止めなければまた元に戻ります。この記事では、増える原因ごとに予防の設定を説明します。WordPressが標準で自動的に行っている処理もあるため、それと重複しない範囲で設定します。内容は2026年10月時点のWordPress 6系を前提にしています。

作業の前に、データベースのバックアップを取ってください。SQLの例は、テーブル接頭辞が wp_ の場合です。wp-config.php の $table_prefix が違う場合は読み替えてください。

WordPressが標準で自動削除しているもの

先に、何もしなくても消えるものを確認しておきます。

対象 標準の動作
期限切れのTransient delete_expired_transients というWP-Cronの処理で1日1回削除される
ゴミ箱の投稿・コメント EMPTY_TRASH_DAYS(既定は30日)を過ぎると、1日1回の処理で削除される
古いリビジョン 上限(WP_POST_REVISIONS)を設定していれば、投稿を保存したときに上限を超えた古いものから削除される
スパムコメント 標準では削除されない(Akismetを使っている場合は、Akismetが古いスパムを削除する)

WP-Cronはサイトへのアクセスをきっかけに動くため、アクセスが少ないサイトや、DISABLE_WP_CRON でWP-Cronを止めてサーバーのcronを設定していないサイトでは、これらの処理が動いていないことがあります。wp cron event list で予定が登録されているか確認できます。

リビジョンの上限を決める

wp-config.php の /* That's all, stop editing! */ より前に書きます。

<?php
// wp-config.php:投稿ごとに残すリビジョンを最新5件までにする
define( 'WP_POST_REVISIONS', 5 );

false にするとリビジョンを作らなくなりますが、誤って上書きしたときに戻せなくなるため、数件は残すことをおすすめします。

投稿タイプごとに変えたい場合は、wp_revisions_to_keep フィルターを使います。このフィルターは WP_POST_REVISIONS より優先されます。

<?php
// 投稿タイプごとに残すリビジョン数を変える(PHP 8.0 以上)
add_filter( 'wp_revisions_to_keep', function ( $num, $post ) {
	return match ( $post->post_type ) {
		'post'    => 5,
		'page'    => 10,
		'product' => 2,
		default   => $num,
	};
}, 10, 2 );

上限を設定しても、すでにある古いリビジョンは、その投稿を次に保存するまで残ります。まとめて整理する方法は、WordPressのリビジョンをデータベースから削除する方法を参照してください。SQLで wp_posts から直接リビジョンを消すと、関連するメタデータが残るため、WordPressの関数やWP-CLIで削除するほうが安全です。

自動保存の間隔について

AUTOSAVE_INTERVAL(既定は60秒)を長くしても、データベースの肥大化はほとんど防げません。自動保存は、投稿とユーザーごとに1件のリビジョンを上書きしていく仕組みで、件数が増えていくものではないためです。間隔を延ばすと、ブラウザーが落ちたときに失われる内容が増えるだけなので、変更は不要です。

Transientを溜めない

期限切れのTransientは、前述のとおりWordPressが1日1回削除します。独自のcronで削除処理を追加する必要は通常ありません。すぐに消したいときは、WP-CLIで実行します。

# 期限切れの Transient だけを削除する
wp transient delete --expired

wp transient delete --all はすべてのTransientを消します。期限のないTransient(有効期限を指定せずに保存されたもの)も消えるため、プラグインが再生成できないデータを保存している場合に不具合が出ることがあります。通常は --expired を使ってください。

SQLで「対応するタイムアウトの行がない _transient_ の行」を消す例を見かけますが、それは有効期限なしで保存された正常なTransientです。期限切れではないものまで消してしまうため、使わないでください。

期限切れのTransientが毎日大量に増える場合は、特定のプラグインが大量に作っていることが多いので、次のSQLで名前の傾向を確認し、プラグインの設定や更新で対処します。

-- Transient の名前の先頭部分ごとに件数を数える
SELECT SUBSTRING_INDEX(option_name, '_', 4) AS prefix, COUNT(*) AS cnt
FROM wp_options
WHERE option_name LIKE '\_transient\_%'
GROUP BY prefix
ORDER BY cnt DESC
LIMIT 20;

RedisやMemcachedの永続オブジェクトキャッシュを使っている場合、Transientはデータベースではなくオブジェクトキャッシュに保存されます。

autoloadオプションを確認する

wp_options テーブルのうち autoload が有効な行は、すべてのページ表示の最初にまとめて読み込まれます。ここが大きくなると、データベースの容量だけでなく表示速度にも影響します。WordPress 6.6以降、autoload の値は yes・no に加えて on・off・auto・auto-on・auto-off が使われます。読み込まれるのは yes・on・auto-on・auto の行です。

-- 自動で読み込まれるオプションの件数と合計サイズ
SELECT COUNT(*) AS cnt,
       ROUND(SUM(LENGTH(option_value)) / 1024, 1) AS size_kb
FROM wp_options
WHERE autoload IN ('yes', 'on', 'auto-on', 'auto');

-- サイズの大きい順に20件
SELECT option_name, autoload,
       ROUND(LENGTH(option_value) / 1024, 1) AS size_kb
FROM wp_options
WHERE autoload IN ('yes', 'on', 'auto-on', 'auto')
ORDER BY LENGTH(option_value) DESC
LIMIT 20;

管理画面の「ツール」→「サイトヘルス」でも、autoload の合計が既定で約800KBを超えると警告が表示されます。

大きな行の名前から、どのプラグインのものかを確認します。すでに削除したプラグインの行であれば、バックアップを取ったうえで削除を検討します。使用中のプラグインの行は、勝手に消したり autoload を変えたりせず、プラグインの設定や作者の案内に従ってください。

自作のコードでオプションを保存するときは、毎回のページ表示で使わないデータなら autoload を無効にします。WordPress 6.7以降、autoload の指定に 'yes'・'no' を使うことは非推奨になっているため、真偽値で指定します。

<?php
// 毎回は使わないデータは autoload を無効にして保存する
add_option( 'my_plugin_log', $data, '', false );
update_option( 'my_plugin_log', $data, false );

スパムコメントと孤立したメタデータを定期的に削除する

スパムコメントは標準では削除されません。Akismetを使っていない場合は、定期的に削除する処理を追加します。ゴミ箱は標準で削除されるため、ここでは扱いません。

次のコードは、テーマを変えても動き続けるよう wp-content/mu-plugins/db-cleanup.php として保存する想定です。

<?php
/*
 * Plugin Name: DB cleanup (spam and orphaned meta)
 */

// 1日1回、スパムコメントと孤立したメタデータを削除する
add_action( 'my_daily_db_cleanup', function () {
	global $wpdb;

	// 30日より前のスパムコメント
	$wpdb->query(
		"DELETE FROM {$wpdb->comments}
		 WHERE comment_approved = 'spam'
		   AND comment_date_gmt < DATE_SUB(UTC_TIMESTAMP(), INTERVAL 30 DAY)"
	);

	// 親のコメントがない commentmeta
	$wpdb->query(
		"DELETE cm FROM {$wpdb->commentmeta} cm
		 LEFT JOIN {$wpdb->comments} c ON cm.comment_id = c.comment_ID
		 WHERE c.comment_ID IS NULL"
	);

	// 親の投稿がない postmeta
	$wpdb->query(
		"DELETE pm FROM {$wpdb->postmeta} pm
		 LEFT JOIN {$wpdb->posts} p ON pm.post_id = p.ID
		 WHERE p.ID IS NULL"
	);
} );

// 予定がなければ登録する(毎日、次の午前4時ごろから)
add_action( 'init', function () {
	if ( ! wp_next_scheduled( 'my_daily_db_cleanup' ) ) {
		wp_schedule_event( strtotime( 'tomorrow 04:00:00' ), 'daily', 'my_daily_db_cleanup' );
	}
} );

strtotime() はPHPのタイムゾーン(WordPressでは通常UTC)で時刻を解釈するため、日本時間の午前4時にはなりません。時刻にこだわる場合は、後述のサーバーのcronで実行してください。

すぐに一度だけスパムを削除したい場合は、WP-CLIでも実行できます。

wp comment delete $(wp comment list --status=spam --format=ids) --force

スパムが数万件ある場合は、引数が長くなりすぎて失敗することがあるため、上の定期処理か、管理画面の「コメント」→「スパム」の「スパムをすべて削除」を使います。

テーブルを定期的に最適化する

行を大量に削除した後のテーブルには、使われていない領域が残ります。WP-CLIの wp db optimize で最適化できます。WP-Cronには「毎月」の標準スケジュールはない(標準は hourly・twicedaily・daily・weekly)ため、サーバーのcronで実行するのが簡単です。

# crontab -e で追加:毎月1日の午前3時に実行
0 3 1 * * cd /var/www/html && /usr/local/bin/wp db optimize --quiet

/var/www/html はWordPressのディレクトリ、/usr/local/bin/wp はWP-CLIの場所に置き換えます(which wp で確認できます)。

WP-Cronで実行したい場合は、cron_schedules フィルターで独自の間隔を追加する必要があります。

<?php
// WP-Cron に「30日ごと」の間隔を追加する
add_filter( 'cron_schedules', function ( $schedules ) {
	$schedules['every_30_days'] = array(
		'interval' => 30 * DAY_IN_SECONDS,
		'display'  => 'Every 30 days',
	);
	return $schedules;
} );

InnoDBのテーブルでは、最適化はテーブルの作り直しになり、大きなテーブルでは時間がかかり負荷も上がります。アクセスの少ない時間帯に実行してください。WP-CLIが使えないレンタルサーバーでは、phpMyAdminのSQL画面で OPTIMIZE TABLE wp_posts; のようにテーブルごとに実行する方法もあります。

まとめ

  • 期限切れTransientとゴミ箱は、WordPressが1日1回自動で削除している。WP-Cronが動いているかを wp cron event list で確認する
  • リビジョンは WP_POST_REVISIONS か wp_revisions_to_keep で上限を決める。AUTOSAVE_INTERVAL の変更は肥大化対策にならない
  • 「タイムアウトのないTransient」をSQLで消さない。期限なしの正常なTransientまで消える
  • autoload は yes・on・auto-on・auto が読み込み対象。自作のオプションは false を指定して保存する
  • スパムコメントと孤立メタデータは、mu-plugin の日次処理で削除する
  • 最適化は wp db optimize をサーバーのcronで月1回実行する。WP-Cronに monthly という標準スケジュールはない

関連記事:

お気軽にご相談ください

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