2026年5月20日

2026年5月20日

WordPressのオプションテーブルが肥大化する場合の対処法

はじめに

WordPressサイトが年々重くなっている、データベースが数GBに膨れ上がっている、管理画面の読み込みが遅い。こうした症状の原因の一つがwp_optionsテーブルの肥大化です。放置すると毎回のページ読み込みで大量のオプションをロードし、サイト全体のパフォーマンスに影響します。

症状・原因

wp_optionsテーブルにはautoload='yes'のレコードがあり、WordPressは起動時に全て読み込みます。プラグインをインストール・削除した後も設定データが残ることが多く、数百万件のレコードが蓄積するケースもあります。

主な原因:

  • プラグインの削除漏れ:アンインストール時にオプションを削除しないプラグイン
  • セッション・一時データ:transientが期限切れ後も残っている
  • リビジョンデータ:投稿の自動下書きデータ
  • キャッシュシステム:設定値を大量にoptionsに保存するプラグイン

解決手順

ステップ1:現状を把握する

まずautoloadされている全レコードのサイズを確認します。

-- autoload合計サイズの確認
SELECT 
    COUNT(*) AS count,
    SUM(LENGTH(option_value)) / 1024 / 1024 AS total_mb,
    SUM(CASE WHEN autoload = 'yes' THEN LENGTH(option_value) ELSE 0 END) / 1024 AS autoload_kb
FROM wp_options;

-- 大きなautoloadレコードを探す
SELECT option_name, LENGTH(option_value) AS size, autoload
FROM wp_options
WHERE autoload = 'yes'
ORDER BY LENGTH(option_value) DESC
LIMIT 20;

ステップ2:期限切れtransientを削除する

# WP-CLIで期限切れtransientを削除
wp transient delete --expired

# 全transientを削除(より積極的)
wp transient delete --all

SQLで直接削除する場合:

-- 期限切れtransientを削除
DELETE FROM wp_options
WHERE option_name LIKE '_transient_timeout_%'
AND option_value < UNIX_TIMESTAMP();

DELETE FROM wp_options
WHERE option_name LIKE '_transient_%'
AND option_name NOT LIKE '_transient_timeout_%'
AND NOT EXISTS (
    SELECT 1 FROM (SELECT * FROM wp_options) tmp
    WHERE tmp.option_name = CONCAT('_transient_timeout_', SUBSTRING(wp_options.option_name, 12))
);

ステップ3:不要なオプションのautoloadをオフにする

// functions.php で特定オプションのautoloadを無効化
// (プラグインが残した不要なautoloadデータ)
add_action('init', function() {
    $options_to_deautoload = [
        'woocommerce_session_data',
        'unnecessary_plugin_cache',
        // 不要なオプション名を追加
    ];
    
    foreach ($options_to_deautoload as $option) {
        if (get_option($option) !== false) {
            $value = get_option($option);
            delete_option($option);
            add_option($option, $value, '', 'no');  // autoload='no'で再登録
        }
    }
});

WP-CLIで一括変更:

# 特定のオプションのautoloadを無効化
wp eval 'global $wpdb; $wpdb->update(
    $wpdb->options,
    ["autoload" => "no"],
    ["option_name" => "problematic_option_name"]
);'

ステップ4:不要なオプションを完全削除する

# 特定のプラグインが残したオプションを削除
wp option delete old_plugin_settings
wp option delete old_plugin_cache_data

# パターンマッチで一括削除
wp eval '
global $wpdb;
$wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE \"old_plugin_%\"");
echo "Deleted: " . $wpdb->rows_affected . " rows\n";
'

ステップ5:データベースを最適化する

# wp_optionsテーブルを最適化
wp db query "OPTIMIZE TABLE wp_options;"

# 全テーブルを最適化
wp db optimize

ステップ6:WP-Cron Job Managerで定期クリーンアップ

// functions.php — 週次で自動クリーンアップ
add_action('wp', function() {
    if (!wp_next_scheduled('cleanup_options_table')) {
        wp_schedule_event(time(), 'weekly', 'cleanup_options_table');
    }
});

add_action('cleanup_options_table', function() {
    // 期限切れtransientを削除
    delete_expired_transients();
    
    // データベースを最適化
    global $wpdb;
    $wpdb->query("OPTIMIZE TABLE {$wpdb->options}");
});

function delete_expired_transients() {
    global $wpdb;
    $wpdb->query(
        "DELETE a, b FROM {$wpdb->options} a, {$wpdb->options} b
        WHERE a.option_name LIKE '_transient_timeout_%'
        AND a.option_value < " . time() . "
        AND b.option_name = CONCAT('_transient_', SUBSTRING(a.option_name, 20))"
    );
}

注意事項

  • SQL直接操作の前に必ずデータベースのバックアップを取ってください。
  • wp_optionsの削除は取り消せません。削除前にオプション名と値を確認しましょう。
  • アクティブなプラグインのオプションは削除しないでください。

まとめ

wp_optionsテーブルの肥大化はWP-CLIでtransientを削除し、不要なautoloadオプションを無効化することで改善できます。定期クリーンアップも設定しておくと継続的なパフォーマンス維持に効果的です。関連記事:WordPressのデータベース最適化transientの使い方

お気軽にご相談ください

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