こんにちは!WordPressの裏側の仕組みやデータベースの最適化に興味を持ってくれて嬉しいです。他の言語からWordPressの世界に入ってきた開発者の中には、「なぜかサイトが重くなってきた」「データが増えると検索が遅くなる」という壁にぶつかる人が多いんですよね。
今回は、そんな悩みを根本から解決する「InnoDBのインデックス・コンプレッション(圧縮)」という、上級プロフェッショナル向けの極限チューニングについてお話しします。
「インデックスの圧縮って難しそう…」と思うかもしれませんが、大丈夫です!基礎から本質まで優しく紐解いていくので、一緒にWordPressのデータベースマスターへの階段を登っていきましょう。ここをクリアすれば、大規模サイトのパフォーマンスチューニングも怖くなくなりますよ!
—
1. なぜ巨大なWordPressサイトでクエリが遅くなるのか?
WordPressの心臓部であるデータベース(MySQL / MariaDB)は、デフォルトのストレージエンジンとして InnoDB を採用しています。
記事数が数万、あるいは数十万件を超えてくると、`wp_posts` や `wp_postmeta` といったテーブルのサイズは爆発的に大きくなります。ここで発行されるのが、おなじみの `WP_Query` ですよね。
// 例:カスタムフィールドの値で投稿を絞り込む典型的な重いクエリ
$args = array(
‘post_type’ => ‘post’,
‘posts_per_page’ => 10,
‘meta_query’ => array(
array(
‘key’ => ‘_my_custom_field’,
‘value’ => ‘target_value’,
),
),
);
$query = new WP_Query( $args );
この `WP_Query` が実行されるとき、裏側では複雑な `JOIN` や `WHERE` 句が生成され、データベースはインデックス(索引)を総当たりで読み込もうとします。
ここでボトルネックになるのが 「ディスクI/O(インプット/アウトプット)」 です。
メモリ(InnoDBバッファプール)上にインデックスが乗り切らなくなると、データベースは遅いストレージ(SSDやHDD)からデータを何度も読み込むことになり、サイト全体のレスポンスがガタ落ちしてしまうのです。
—
2. 救世主「インデックス・コンプレッション」とは何か?
そこで登場するのが、InnoDBの インデックス・コンプレッション(Page Compression / Table Compression) です。
イメージ図で考えてみましょう。
[通常のインデックス構造]
+————————————————-+
| [巨大なインデックスデータ] (メモリに乗り切らない!) | -> ディスクI/O多発 😭
+————————————————-+
[インデックス・コンプレッション適用後]
+———————–+
| [圧縮されたインデックス] | -> メモリ効率が2倍に!ヒット率向上 🚀
+———————–+
インデックス・コンプレッションとは、データベースのページ単位(通常16KB)でデータを圧縮して保存する技術です。
メリット
- メモリヒット率の劇的な向上: データサイズが小さくなるため、より多くのインデックスを高速なメモリ(バッファプール)上に載せられます。
- ディスクI/Oの削減: 物理的な読み込み回数が減り、CPUの処理能力を最大限に活かせます。
デメリット(トレードオフ)
- CPU負荷の上昇: データの読み書き時に「圧縮・解凍」の処理が挟まるため、わずかにCPUリソースを消費します。
つまり、「CPUに少し余裕があって、メモリ不足やディスクI/Oに悩んでいる大規模サイト」においては、これ以上ない強力な武器になるというわけですね。
—
3. 実践:WordPressの特定テーブルを圧縮してみよう
それでは、実際にデータベース側の設定を変更してみましょう。
※作業を行う前には、必ずデータベースのフルバックアップを取ってくださいね!
ここでは、メタ情報が膨らみがちな `wp_postmeta` テーブルのインデックス効率を意識しつつ、テーブル全体(または圧縮対象のインデックス)に対して圧縮を有効化するSQLの例を見てみましょう。
— InnoDBのテーブル作成・変更時に ROW_FORMAT=COMPRESSED を指定します
ALTER TABLE wp_postmeta
ROW_FORMAT = COMPRESSED
KEY_BLOCK_SIZE = 8; — デフォルト16KBのページを8KBに圧縮してメモリ効率を上げる
コードの意味
- `ROW_FORMAT = COMPRESSED`: このテーブルでページ圧縮機能を使用することを宣言しています。
- `KEY_BLOCK_SIZE = 8`: 圧縮後のページサイズを指定しています(4, 8, 16 が指定可能)。小さすぎると逆に圧縮・解凍のオーバーヘッドが増えるため、通常は `8` から始めるのが安全です。
—
4. 陥りやすい罠と文法エラー
データベースレベルでチューニングを行う際、他の言語からの開発者がやりがちなミスや、WordPress特有の注意点があります。
エラーその1: `innodb_file_per_table` が無効になっている
MySQLのデフォルト設定によっては、圧縮テーブルを作成しようとした際に以下のようなエラーが出ることがあります。
> `ERROR 1005 (HY000): Can’t create table … (errno: 140 “Tablespace-denied”)`
対策:
`my.cnf`(設定ファイル)で、個別のテーブルスペース作成が有効になっているか確認してください。
[mysqld]
innodb_file_per_table = 1
エラーその2: 圧縮しすぎてCPUが悲鳴を上げる
「小さければ小さいほど良い」と `KEY_BLOCK_SIZE = 4` などを安易に指定すると、CPU使用率(Load Average)が跳ね上がり、かえって `WP_Query` の実行速度が遅くなる本末転倒な現象が起きます。
先輩からのアドバイス:
本番環境に適用する前に、必ずステージング環境で `EXPLAIN` を使ったクエリの挙動確認や、負荷テスト(Apache BenchやJMeterなど)を行い、CPUとメモリのバランスを計測するようにしましょう。
—
5. WP_Queryのパフォーマンスをさらに引き出すアプローチ
データベースのインデックスを最適化したら、それを叩く `WP_Query` 側もスマートにしてあげましょう。無駄なクエリを発行しないことが、データベース負荷軽減の最大の近道です。
例えば、カスタムフィールドを複数条件で検索する際、デフォルトの `WP_Query` は非効率なJOINを生成しがちです。以下のように、必要なデータだけをキャッシュや適切なロジックで取得する意識を持ちましょう。
/
- 効率的なWP_Queryの書き方の例
- 不要なSQLの結合を避け、インデックスが効きやすい条件設計にする
/
$optimized_query = new WP_Query( array(
‘post_type’ => ‘product’,
‘posts_per_page’ => 12,
// 変更不可能なプライマリキーや、適切にインデックスされたカラムを条件に使う
‘orderby’ => ‘date’,
‘order’ => ‘DESC’,
// データベースのキャッシュ(Object Cacheなど)を併用する前提の設計にする
‘no_found_rows’ => true, // ページネーションの総件数計算(SQL_CALC_FOUND_ROWS)をスキップして高速化!
) );
if ( $optimized_query->have_posts() ) {
while ( $optimized_query->have_posts() ) {
$optimized_query->the_post();
// テンプレート描画処理
}
}
wp_reset_postdata();
ここで使った `’no_found_rows’ => true` は、大規模サイトの `WP_Query` チューニングにおいて必須のテクニックです。全件カウントのクエリ発行を省くことで、InnoDBへの負担を大きく減らすことができますよ。
—
まとめ
今回は、InnoDBのインデックス・コンプレッションを通じて、巨大なWordPressデータベースを高速化するアプローチを解説しました。
1. 巨大なテーブルと `WP_Query` はディスクI/Oがボトルネックになる
2. インデックス・コンプレッションでメモリヒット率を向上させられる
3. `KEY_BLOCK_SIZE` の設定やCPU負荷とのトレードオフに注意する
4. `no_found_rows` などのWP_Query最適化テクニックを組み合わせる
データベースの内部構造まで踏み込んで最適化できるようになると、WordPressで見られないほどの巨大メディアサイトやECサイトも自由自在にコントロールできるようになります。
一歩一歩着実に知識を自分のものにしていけば、あなたも間違いなく一流のWordPressエンジニアになれますよ。次回の解説もお楽しみに!