2026年8月21日
2026年8月21日
WordPressのデータベース肥大化を防ぐ方法
はじめに
データベースの肥大化は一度問題が起きてから対処するより、日常的な予防策で積み重ませない方が効果的です。リビジョン・Transient・autoloadオプション・スパムコメントの4つを制御するだけで、DBサイズを長期にわたって安定させられます。
症状・原因
- サイト運用年数が長くなるにつれDBサイズが増え続けている
- 削除しても数ヶ月後にまた肥大化している
- バックアップが大きくなり保管コストが増えている
- 定期メンテナンスの仕組みがなく手作業に頼っている
解決手順
ステップ1:リビジョンを最初から制限する
// wp-config.php: リビジョン蓄積を根本から防ぐ
// 投稿タイプ問わず最新3件のみ保持
define('WP_POST_REVISIONS', 3);
// 自動保存間隔を60秒→5分に延長(autosave 件数削減)
define('AUTOSAVE_INTERVAL', 300);
// functions.php: 投稿タイプ別に細かく制御
add_filter('wp_revisions_to_keep', function(int $num, WP_Post $post): int {
return match($post->post_type) {
'post' => 5,
'page' => 10,
'product' => 2,
default => 3,
};
}, 10, 2);
ステップ2:Transientを自動削除・発生を抑制する
// functions.php: 期限切れTransientを週次で削除
add_action('weekly_transient_cleanup', function(): void {
global $wpdb;
$wpdb->query(
"DELETE FROM {$wpdb->options}
WHERE option_name LIKE '_transient_timeout_%'
AND option_value < UNIX_TIMESTAMP()"
);
$wpdb->query(
"DELETE FROM {$wpdb->options}
WHERE option_name LIKE '_transient_%'
AND option_name NOT LIKE '_transient_timeout_%'
AND option_name NOT IN (
SELECT REPLACE(option_name, '_timeout', '')
FROM (SELECT option_name FROM {$wpdb->options}
WHERE option_name LIKE '_transient_timeout_%') AS t
)"
);
});
if (!wp_next_scheduled('weekly_transient_cleanup')) {
wp_schedule_event(time(), 'weekly', 'weekly_transient_cleanup');
}
# WP-CLI で即時削除
wp transient delete --expired
# 全Transientを削除(キャッシュが不要な場合)
wp transient delete --all
ステップ3:autoloadオプションを管理する
-- autoload サイズを確認
SELECT
autoload,
COUNT(*) AS count,
ROUND(SUM(LENGTH(option_value)) / 1024, 1) AS size_kb
FROM wp_options
GROUP BY autoload;
-- 大きな autoload=yes のオプションを特定
SELECT option_name,
ROUND(LENGTH(option_value) / 1024, 1) AS size_kb,
autoload
FROM wp_options
WHERE autoload = 'yes'
AND LENGTH(option_value) > 10240 -- 10KB以上
ORDER BY LENGTH(option_value) DESC
LIMIT 20;
// 新規オプション登録時は autoload=false を明示する
// ❌ デフォルトは autoload=yes
add_option('my_plugin_data', $data);
// ✅ 不要な自動読み込みを避ける
add_option('my_plugin_data', $data, '', 'no');
update_option('my_plugin_data', $data, false);
ステップ4:スパム・ゴミ箱を自動削除する
// functions.php: スパム・ゴミ箱の定期自動削除
add_action('daily_db_cleanup', 'run_daily_db_cleanup');
function run_daily_db_cleanup(): void {
global $wpdb;
// 30日超スパムコメントを削除
$wpdb->query(
"DELETE FROM {$wpdb->comments}
WHERE comment_approved = 'spam'
AND comment_date < DATE_SUB(NOW(), INTERVAL 30 DAY)"
);
// 7日超ゴミ箱コメントを削除
$wpdb->query(
"DELETE FROM {$wpdb->comments}
WHERE comment_approved = 'trash'
AND comment_date < DATE_SUB(NOW(), INTERVAL 7 DAY)"
);
// 孤立した commentmeta を削除
$wpdb->query(
"DELETE pm FROM {$wpdb->commentmeta} pm
LEFT JOIN {$wpdb->comments} c ON pm.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"
);
}
if (!wp_next_scheduled('daily_db_cleanup')) {
wp_schedule_event(strtotime('tomorrow 04:00:00'), 'daily', 'daily_db_cleanup');
}
ステップ5:月次 OPTIMIZE TABLE でフラグメンテーションを防ぐ
// functions.php: 月次テーブル最適化
add_action('monthly_db_optimize', 'optimize_wp_tables');
function optimize_wp_tables(): void {
global $wpdb;
$tables = $wpdb->get_results(
"SELECT table_name, data_free
FROM information_schema.tables
WHERE table_schema = DATABASE()
AND data_free > 5242880", // 5MB以上のオーバーヘッドのみ
ARRAY_A
);
foreach ($tables as $table) {
$wpdb->query("OPTIMIZE TABLE `{$table['table_name']}`");
}
update_option('last_db_optimize', current_time('mysql'), false);
}
if (!wp_next_scheduled('monthly_db_optimize')) {
// 毎月1日 AM 3:00 に実行
$first_of_month = mktime(3, 0, 0, (int)date('n'), 1, (int)date('Y'));
if ($first_of_month < time()) {
$first_of_month = mktime(3, 0, 0, (int)date('n') + 1, 1, (int)date('Y'));
}
wp_schedule_event($first_of_month, 'monthly', 'monthly_db_optimize');
}
# crontab で月次 OPTIMIZE(サーバー直接実行の場合)
# 毎月1日 AM3:00 に実行
0 3 1 * * wp --path=/var/www/html db optimize
注意事項
WP_POST_REVISIONS=3に設定しても、既存の古いリビジョンは削除されません。別途DELETE FROM wp_posts WHERE post_type='revision'で既存分を整理してくださいOPTIMIZE TABLEはInnoDB形式のテーブルでは実際にはテーブル再構築(ALTER TABLE ... FORCE相当)が走るため、大きなテーブルではI/Oが増加します。アクセスの少ない夜間に実行してください- Transientはプラグインのキャッシュとして使われているため、全削除するとページキャッシュが一時的に消える場合があります。
--expiredオプションで期限切れのみ削除するのが安全です
まとめ
DBの肥大化予防は①WP_POST_REVISIONS=3とAUTOSAVE_INTERVAL=300でリビジョン上限を設定、②wp transient delete --expiredと週次cronで期限切れTransientを継続削除、③新規add_optionにautoload='no'を明示して不要な自動読み込みを防止、④daily cronで30日超スパム・7日超ゴミ箱・孤立postmeta/commentmetaを自動削除、⑤月次cronでオーバーヘッド5MB超のテーブルのみOPTIMIZE TABLEを実施します。