こんにちは!WordPressの裏側の仕組みやデータベースの挙動に興味を持ってくれて嬉しいです。他のプログラミング言語を触ったことがある人なら、「データベースのインデックス(索引)」という言葉を聞いたことがあるかもしれませんね。
今回は、WordPressの心臓部である `WP_Query` において、`post_status`(投稿ステータス)の指定がデータベースの検索速度、そしてインデックスにどのような影響を与えるのかを一緒に紐解いていきましょう。
ここをクリアすれば、WordPressのパフォーマンスの基本はバッチリマスターできますよ!ぜひ最後までついてきてくださいね。
—
1. なぜ `post_status` が重要なのか?
WordPressでブログやWebサイトを作るとき、最もよく使うデータ取得の仕組みが `WP_Query` ですよね。
例えば、「公開済みの最新記事を5件取得したい」と思ったとき、あなたならどう書きますか? きっとこんなコードを書くはずです。
$args = array(
‘post_type’ => ‘post’,
‘posts_per_page’ => 5,
// post_statusを指定していない(デフォルトは ‘publish’)
);
$query = new WP_Query( $args );
このとき、WordPressの内部(MySQL)では一体何が起きているでしょうか? ここが今回の最も重要なポイントです。
—
2. 内部発行されるSQLの決定的な違い
初心者の方が陥りがちな誤解として、「何も指定しないんだから、WordPressが勝手にいい感じに軽くしてくれるんでしょ?」というものがあります。実は、ステータスの指定方法によって、MySQLが実行するSQL文(=検索のやり方)がガラリと変わるんです。
パターンA:公開済み(’publish’)だけを検索する場合
先ほどのように `post_status` を省略するか、あえて `’publish’` と指定した場合、内部のSQLは次のような条件で発行されます。
— イメージ:単一ステータス検索のSQL
SELECT FROM wp_posts
WHERE post_type = ‘post’
AND post_status = ‘publish’
ORDER BY post_date DESC
LIMIT 5;
パターンB:すべてのステータスを検索する場合
もし、予約投稿や下書きも含めて「すべてのステータス」を検索対象にしたいと意図して、あるいは無意識に以下のように書いたとします。
$args = array(
‘post_type’ => ‘post’,
‘post_status’ => ‘any’, // すべてのステータス
‘posts_per_page’ => 5,
);
このとき、MySQLが裏側で実行するSQLは、大雑把に言うとこのような形に変化します。
— イメージ:複数ステータス検索のSQL(IN句やOR条件の多用)
SELECT FROM wp_posts
WHERE post_type = ‘post’
AND post_status IN (‘publish’, ‘pending’, ‘draft’, ‘private’, ‘future’, ‘trash’)
ORDER BY post_date DESC
LIMIT 5;
この2つのSQL、パッと見の違いは `post_status = ‘publish’` なのか `post_status IN (…)` なのか、という点だけに見えますよね。しかし、これがデータベースのインデックス効率において天と地ほどの差を生むんです。
—
3. インデックスの仕組みと「全件スキャン」の罠
ここで、データベースのインデックス(索引)について少しイメージしてみましょう。
本(データベースのテーブル)の後ろについている「索引(インデックス)」を思い浮かべてください。「あ」から始まる言葉がどこにあるか一発で引けますよね。MySQLの `wp_posts` テーブルの `post_status` や `post_type` にも、こうしたインデックスが張られています。
- `post_status = ‘publish’` の場合:
MySQLは「あ」のページを開くように、一瞬で「`publish`」の行が集まっている場所へジャンプできます(これを Index Lookup と呼びます)。爆速です。
- `post_status IN (…)` や `post_status != ‘trash’` の場合:
条件が複雑になると、データベースのオプティマイザ(頭脳)は「インデックスを使うより、全ページを1枚ずつめくった方が早いかもしれない…」と判断してしまいます。これが テーブルのフルスキャン(全件走査) です。
記事数が数万件を超えてくると、このフルスキャンが原因でデータベースのCPU使用率が跳ね上がり、サイト全体が重くなるという悲劇が起きるんです。
—
4. ありがちな文法・設計エラーと対策
開発現場でよく見かける「やってはいけない書き方」と、その正しいアプローチを見ていきましょう。
❌ やってはいけない例:不要な `post_status` の指定
「念のため全ステータスを対象にしておこう」という軽い気持ちで `’post_status’ => ‘any’` や、すべてのステータスを配列で列挙してしまうケースです。
// 【NG例】公開側(フロントエンド)のループなのに、すべてのステータスを指定している
$args = array(
‘post_type’ => ‘post’,
‘post_status’ => array( ‘publish’, ‘draft’, ‘pending’ ), // 重いクエリになりがち
);
$query = new WP_Query( $args );
なぜダメなのか?
フロントエンド(一般ユーザーが見る画面)で下書きや保留中の記事が表示される必要は基本的にありませんよね。不要な条件を増やすことで、データベースに無駄な負荷をかけ、インデックスの効き目を悪くしてしまいます。
⭕ 正しい例:用途に合わせた最小限の指定
フロントエンドの通常の記事一覧であれば、余計な指定はせず、デフォルト(=公開済み)に任せるのが一番の最適化です。
// 【OK例】フロントエンドでは必要最小限のクエリにする
$args = array(
‘post_type’ => ‘post’,
‘posts_per_page’ => 10,
// post_status はあえて書かない(自動的に ‘publish’ に絞られ、インデックスが最速で効く)
);
$query = new WP_Query( $args );
もし管理画面や特別な権限を持つユーザー向けに、あえて下書きなども含めて取得したい場合のみ、意図して `post_status` をコントロールするようにしましょう。
—
まとめ
今回は、`WP_Query` における `post_status` とインデックスの関係について解説しました。
1. 基本は「公開済み(`publish`)」のみ: フロントエンドでは余計なステータスを指定せず、データベースのインデックスを最大限に活かしましょう。
2. `any` や複数指定は慎重に: 検索条件が複雑になると、フルスキャンが発生してサイトのパフォーマンス低下を招きます。必要な場所だけで使うのがプロの技です。
「なぜこの引数を書くのか」「データベースは裏でどう動いているのか」を意識できるようになると、書くコードの質が劇的に変わります。
ここをクリアすれば、もうあなたコーディングの基本はバッチリマスターできていますよ!自信を持って次のステップに進んでいきましょう。それでは、また次の知見でお会いしましょう!