【入門編】実務中級者向け:WP_Queryの「post_parent」検索を高速化するインデックスの貼り方 – WordPress 内部コア・データベース構造とパフォーマンス最適化解析バイブル

こんにちは!WordPressの裏側の仕組みやデータベースとの対話に興味を持ってくれて嬉しいです。他の言語からやってくると、「WordPressってなんだかマジックが多すぎて、裏で何が起きているか見えにくいな…」と感じることも多いですよね。すごくよく分かります。

今回は、実務でも非常によく使う階層構造の検索、その中でも`WP_Query`の`post_parent`検索を爆速にするインデックスの貼り方について、データベースの内部構造まで踏み込んで一緒に見ていきましょう!

ここをクリアできれば、単なる「使い方を知っている人」から「データベースの挙動までコントロールできるエンジニア」へと一歩ステップアップできますよ。ぜひ最後までついてきてくださいね。

—

1. なぜ `post_parent` 検索は重くなるのか?

WordPressで固定ページ(Page)やカスタム投稿タイプを使って、親子関係(階層構造)を表現することはよくありますよね。例えば、「親ページIDが `123` の子ページ一覧を取得したい」という時、私たちは次のようなコードを書きます。

// 親IDが 123 の子ページを取得するおなじみの書き方
$args = array(
‘post_type’ => ‘page’,
‘post_parent’ => 123,
‘posts_per_page’ => -1,
);
$child_query = new WP_Query( $args );

このコード、数件程度の投稿数であれば一瞬で終わります。でも、サイトが成長して投稿数が数万件、数十万件になってくると、このクエリが急に重くなり、サーバーのCPU使用率が跳ね上がったり、スロークエリとしてログに記録されたりするようになります。

一体、データベース(MySQL / MariaDB)の内部では何が起きているのでしょうか?

裏側で発行されているSQLの正体

`WP_Query` が実行されると、WordPressは内部で次のようなSQL文を組み立ててデータベースに投げます(※分かりやすく簡略化しています)。

SELECT
FROM wp_posts
WHERE post_parent = 123
AND post_type = ‘page’
AND post_status = ‘publish’;

データベースの気持ちになって考えてみましょう。もし、`wp_posts` テーブルの `post_parent` カラムにインデックス(索引)が貼られていなかったらどうなるでしょうか?

データベースは、お目当ての親IDを見つけるために、テーブルの一番上から一番下まで、すべての行を1件ずつ順番に確認していきます(これをフルテーブルスキャンと呼びます)。数万行のフルテーブルスキャンが走るたびに、サーバーは汗をかいて処理遅延を引き起こしてしまうんです。

—

2. データベースのインデックスってなに?(イメージ図解)

インデックス(Index)は、本でいうところの「巻末の索引(さくいん)」だと思ってください。

【インデックスなし(フルテーブルスキャン)】
1行目を見に行く → 違う → 2行目を見に行く → 違う → …(全行走査)

【インデックスあり(高速検索)】
「post_parent = 123」はどこにある?
↓ 索引を見る
「この行番号(アドレス)に飛べば一発だよ!」と瞬時に特定

WordPressのコアテーブルである `wp_posts` には、デフォルトでいくつかのインデックス(プライマリキーや `post_name` など)が用意されていますが、実は単体の `post_parent` カラムにはインデックスが標準では貼られていません。

そのため、階層構造を多用する大規模サイトでは、ここをチューニングしてあげる必要があるのです。

—

3. 実践!高速化のための「複合インデックス」設計

単に `post_parent` だけにインデックスを貼るのも一つの手ですが、実務の `WP_Query` を見ると、大抵は次のような条件がセットになっています。

1. `post_type` (投稿タイプは何か)
2. `post_status` (公開されているか)
3. `post_parent` (親は誰か)

ここで登場するのが、複数のカラムを組み合わせて作る「複合インデックス(Composite Index)」です。

最適なインデックスの作成SQL

データベース管理ツール(phpMyAdminやWP-CLI、Sequel Aceなど)を使って、`wp_posts` テーブルに以下のSQLを実行します。

— post_type, post_status, post_parent の順番で複合インデックスを追加する
ALTER TABLE wp_posts
ADD INDEX idx_type_status_parent (post_type, post_status, post_parent);

なぜこの順番(`post_type` -> `post_status` -> `post_parent`)なのか?

データベースの複合インデックスは、左側のカラムから順番に絞り込みを行っていくという性質(左端プレフィックスの法則)があります。

`WP_Query` は通常、特定の投稿タイプ(例: `page`)と公開ステータス(例: `publish`)を指定することが多いため、カーディナリティ(データの重複度合いが低い=種類が多いもの)や検索条件の絞り込みやすさを考慮して、左側に `post_type` と `post_status` を置き、その上で特定の `post_parent` をスパッと特定できるようにこの並び順が最も効率的になります。

—

4. 陥りやすい文法・設計エラーと注意点

データベースのチューニングには、初心者の方がやりがちな「落とし穴」がいくつかあります。ここでしっかり押さえておきましょう。

1. プレフィックス(接頭辞)の確認を忘れる

ご自身のWordPress環境のテーブル名が、デフォルトの `wp_` ではなく、セキュリティ対策などで `wp_abc123_` のようになっている場合があります。SQLを書く際は、必ず実際のテーブル名(`$wpdb->posts` が指す名前)を確認してくださいね。

2. インデックスを「とりあえず全部に貼る」のはNG

「じゃあ、すべてのカラムにインデックスを貼れば最強じゃん!」と思いがちですが、それは大きな間違いです。
インデックスは検索を速くする一方で、新しい投稿を追加(INSERT)したり、更新(UPDATE)したりする時には、インデックスのツリー構造も毎回更新し直す必要があるため、書き込み速度が低下します。
「頻繁に検索されるけれど、更新頻度はそこまで爆発的ではない条件」を見極めてピンポイントで貼るのが、シニアエンジニアの技の見せ所です。

3. `EXPLAIN` でクエリの実行計画を確認する癖をつけよう

「本当にインデックスが効いているのか?」を確認するには、SQL文の頭に `EXPLAIN` をつけて実行します。

EXPLAIN
SELECT
FROM wp_posts
WHERE post_parent = 123
AND post_type = ‘page’
AND post_status = ‘publish’;

実行結果の `key` カラムに、今回作成した `idx_type_status_parent` が表示されていれば、データベースが無事にインデックスを使って検索してくれている証拠です!やったね!

—

5. まとめ

今回は、`WP_Query` の `post_parent` 検索を高速化するためのインデックス設計について解説しました。

  • 課題: 投稿数が増えると `post_parent` の検索(フルテーブルスキャン)がボトルネックになる。
  • 解決策: `post_type`, `post_status`, `post_parent` を網羅した複合インデックスを貼る。
  • 本質: クエリが裏側でどういうSQLを発行し、データベースがどうデータを走査しているかを想像する。

ここを理解できれば、単に動くコードを書くだけでなく、「スケールする(耐えうる)WordPressサイト」を設計できるようになります。

「ここをクリアすれば、WordPressのデータベース周りの基本はバッチリマスターできますよ!」
ぜひ、ステージング環境などで試してみてくださいね。あなたのエンジニアライフを応援しています!

タイトルとURLをコピーしました