2026年8月28日

2026年8月28日

WordPressのDBでANALYZE TABLEを使い統計情報を最新化する方法と定期実行の設定

ANALYZE TABLE は、MySQL / MariaDB がクエリの実行計画を決めるときに使う「統計情報」(各インデックスに何種類の値があるかなどの見積もり)を更新するコマンドです。データを書き換えるものではなく、大量削除や一括インポートのあとに実行計画が急に悪くなったときの対処として有効です。この記事では、統計情報が古くなると何が起きるか、いつ実行すべきか、手動実行と cron での定期実行の方法、OPTIMIZE TABLE との違いを説明します。

統計情報が古いと何が起きるか

MySQL のオプティマイザは、同じ SQL でも「どのインデックスを使うか」「どのテーブルから JOIN するか」を統計情報をもとに選びます。統計が実態とずれると、本来は数件で済む検索でテーブル全体を読む計画を選んでしまうことがあります。WordPress で起きやすい場面は次のとおりです。

  • リビジョンや期限切れトランジェント、スパムコメントを大量に削除した直後
  • WooCommerce の商品やユーザーを一括インポートした直後
  • 新しいインデックスを追加した直後
  • 特定の一覧ページだけが、ある日を境に急に遅くなった

症状としては、EXPLAIN の rows(読み取る行数の見積もり)が実際の件数と大きく食い違う、key 列に期待したインデックスが出ない、といった形で現れます。

InnoDB の統計情報の仕組み

現在の WordPress で一般的な InnoDB では、統計情報はテーブル全体を数えるのではなく、一部のページを抜き出して見積もる方式です。MySQL 5.6 以降は既定で統計情報をディスクに保存する「永続統計」が有効になっており、関連する設定は次のとおりです。

  • innodb_stats_persistent: 統計を mysql.innodb_table_stats / mysql.innodb_index_stats に保存するかどうか。既定で有効
  • innodb_stats_auto_recalc: テーブルの行の約10%が変更されると自動で再計算する設定。既定で有効
  • innodb_stats_persistent_sample_pages: 見積もりに使うページ数。増やすと精度は上がり、ANALYZE TABLE の所要時間も延びる

自動再計算があるため、通常の運用で頻繁に手動実行する必要はありません。ただし再計算は非同期で行われるため、大量更新の直後は古い統計のまま実行計画が決まることがあります。また、変更が10%未満でも分布が偏るような更新では自動再計算が走りません。こうした場面で手動の ANALYZE TABLE が役に立ちます。既定値はバージョンによって異なることがあるため、実際の値は SHOW VARIABLES LIKE 'innodb_stats%'; で確認してください。

現在の統計を確認する

統計がいつ更新されたかは、永続統計のテーブルで確認できます。データベース名とテーブル接頭辞は環境に合わせてください。

SELECT database_name, table_name, n_rows, last_update
FROM mysql.innodb_table_stats
WHERE database_name = 'your_db_name'
ORDER BY last_update;

n_rows は見積もりの行数です。SELECT COUNT(*) の結果と大きくずれているテーブルや、last_update が大量削除より前のままのテーブルが更新候補です。共用サーバーでは mysql データベースを読む権限がないことが多いため、その場合は SHOW INDEX FROM wp_postmeta; の Cardinality 列(値の種類の見積もり)を見て判断します。

ANALYZE TABLE を手動で実行する

ANALYZE TABLE wp_posts, wp_postmeta, wp_options;

結果の Msg_text が OK なら完了です。InnoDB では抜き取り方式のため、大きなテーブルでも通常は短時間で終わります。実行中は読み取りは可能ですが、書き込みとの競合で一時的に待ちが生じることがあるため、アクセスの少ない時間帯に行います。

注意したいのは、長時間実行中のクエリがあるテーブルに ANALYZE TABLE をかけると、後続のクエリが待たされる事例が知られている点です(MySQL のバージョンにより挙動が異なります)。実行前に SHOW PROCESSLIST; で長く動いているクエリがないかを確認してください。

WP-CLI が使える環境なら、wp-config.php の接続情報をそのまま使って実行できます。

wp db query "ANALYZE TABLE wp_posts, wp_postmeta;"

レプリケーション構成では、ANALYZE TABLE は既定でバイナリログに書かれ、レプリカでも実行されます。プライマリだけで実行したい場合は ANALYZE NO_WRITE_TO_BINLOG TABLE ...(または LOCAL)を使います。

cron で定期実行する

大量削除のような作業を定期的に行っているサイトでは、その後に ANALYZE TABLE を組み込むと効果的です。単独で定期実行する場合は、週1回程度の深夜帯が目安です。mysqlcheck の --analyze を使うと、データベース内の全テーブルをまとめて処理できます。

パスワードをコマンドラインや crontab に書くと、プロセス一覧や履歴から読み取られるおそれがあります。実行ユーザーのホームに接続情報のファイルを作り、本人だけが読めるようにしておきます。

# ~/.my.cnf(chmod 600 にする)
[client]
user=your_db_user
password=your-db-password
# crontab -e で登録する例: 毎週日曜 4:30 に実行し、結果をログへ
30 4 * * 0 /usr/bin/mysqlcheck --analyze your_db_name >> /var/log/mysql-analyze.log 2>&1

MySQL の場合は mysql_config_editor で暗号化した接続情報(ログインパス)を使う方法もあります。登録後は一度手動で同じコマンドを実行し、ログに各テーブルの OK が並ぶことを確認してください。

OPTIMIZE TABLE との違い

名前が似ていますが、目的と負荷が異なります。

  • ANALYZE TABLE: 統計情報だけを更新します。データの並び替えはしないため軽く、実行計画の改善が目的です。
  • OPTIMIZE TABLE: InnoDB ではテーブルを作り直して断片化を解消し、空き領域を詰めます(あわせて統計も更新されます)。テーブルサイズに比例して時間がかかり、一時的にテーブルと同程度のディスク容量を使います。

WP-CLI の wp db optimize や、WP-Optimize などのデータベース最適化プラグインが実行するのは主に OPTIMIZE 側の処理です。「実行計画がおかしい」という問題に対しては、まず軽い ANALYZE TABLE を試し、容量の回収が目的のときに OPTIMIZE TABLE を計画的に実行する、という使い分けが安全です。いずれもデータベースのバックアップを取ってから行ってください。

統計を更新しても遅いとき

ANALYZE TABLE で解決するのは「見積もりのずれ」が原因の場合だけです。統計を更新しても EXPLAIN の結果が変わらない場合は、インデックスがそもそも使えない条件(meta_value の数値比較や部分一致など)になっているか、インデックスが足りていない可能性があります。

MySQL 8.0 以降ではインデックスのない列についてヒストグラムを作れる ANALYZE TABLE ... UPDATE HISTOGRAM ON 列名 が、MariaDB ではエンジンに依存しない統計(ANALYZE TABLE ... PERSISTENT FOR ALL)が使えます。どちらも効果はクエリによって異なるため、ステージングで EXPLAIN の変化を確認してから本番に適用します。利用できる機能はバージョンで異なります(2026年10月現在)。

まとめ

  • ANALYZE TABLE は実行計画の判断材料である統計情報を更新するだけで、データは変更しない
  • InnoDB は自動再計算があるが、大量削除・一括インポート・インデックス追加の直後は手動実行が有効
  • 実行前に長時間クエリの有無を確認し、レプリケーション環境ではバイナリログへの記録に注意する
  • 定期実行は mysqlcheck --analyze を cron に登録し、パスワードは権限600の接続情報ファイルに置く
  • OPTIMIZE TABLE は重い別物。統計の問題には ANALYZE TABLE を先に試す

お気軽にご相談ください

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