こんにちは!WordPressの裏側の仕組みや、パフォーマンスチューニングの世界へようこそ。
他のプログラミング言語やモダンなフレームワークからWordPressに入ってきた開発者の中には、「なんとなく `WP_Query` や `get_posts()` を使っているけれど、データ量が増えてくるとサイトが重くなる……」という壁にぶつかった方も多いのではないでしょうか。
今回は、大規模なデータセットを扱う際に避けて通れない、「メモリ消費量とデータベース負荷の最適化」について深く掘り下げていきます。
特に、「記事のIDだけが欲しいとき」によく使われる `fields => ‘ids’` と、お手軽な `get_posts()` の違いを、WordPressの内部挙動(コアの動き)まで踏み込んで比較してみましょう。ここをクリアすれば、あなたも確実にワンランク上のWordPressエンジニアになれますよ。一緒にしっかりマスターしていきましょう!
—
なぜWordPressのクエリ最適化が必要なのか?
まずは、WordPressが裏側で何をしているのか、その基本をイメージしてみましょう。
私たちが `new WP_Query()` や `get_posts()` を実行すると、WordPressはデータベース(MySQL)に対して `SELECT FROM wp_posts …` のようなクエリを投げます。そして、返ってきた膨大なデータを元に、一つひとつ `WP_Post` という「オブジェクト(実体)」をPHPのメモリ上に生成します。
これを図解すると、こんなイメージです。
[ MySQL データベース ]
│
▼ (SELECT 全カラム取得)
[ PHP メモリ空間 ]
│
├─ [ WP_Post オブジェクト A ] (タイトル、本文、カスタムフィールド、スラッグ…)
├─ [ WP_Post オブジェクト B ] (タイトル、本文、カスタムフィールド、スラッグ…)
└─ [ WP_Post オブジェクト C ] (タイトル、本文、カスタムフィールド、スラッグ…)
もし、トップページやサイトマップ、あるいは一括処理で「最新記事のIDを1000件取得したいだけ」なのに、上記のようにすべての記事オブジェクト(本文やメタデータ含む)をメモリ上に展開してしまったらどうなるでしょうか?
当然、PHPのメモリ制限(Memory Limit)を圧迫し、最悪の場合は「Allowed memory size of … exhausted」という致命的なエラーを引き起こしてしまいます。これが、大規模サイトでパフォーマンスが低下する最大の原因の一つです。
—
1. `get_posts()` の基本と、その裏側の挙動
まずは、普段よく使う `get_posts()` についておさらいしておきましょう。
`get_posts()` は、内部で `WP_Query` をラップして使いやすくした関数です。「コードをすっきり書ける」という理由から、多くの開発現場で愛用されていますよね。
基本的な使い方とコードの意味
5, // 取得する件数
‘category’ => 5, // カテゴリID
‘orderby’ => ‘date’, // 日付順
‘order’ => ‘DESC’, // 降順(新しい順)
) );
foreach ( $recent_posts as $post ) {
// $post は WP_Post オブジェクトです
echo esc_html( $post->post_title ) . ‘
‘;
}
`get_posts()` の本質:手軽だけど「全部入り」
`get_posts()` はデフォルトの状態だと、`fields` パラメータが指定されていないため、データベースから記事全体の情報(すべてのカラム)を取得し、それを `WP_Post` クラスのインスタンス(オブジェクト)に変換して返します。
数件〜数十件程度の取得であれば何の問題もありませんが、数千件規模のループを回すようなバッチ処理やAPIのエンドポイント開発では、この「オブジェクト生成コスト」がじわじわと効いてきます。
—
2. `WP_Query` の `fields => ‘ids’` による超軽量化
では、メモリ消費を極限まで抑えたい場合はどうすればよいでしょうか?
ここで登場するのが、`WP_Query`(または `get_posts()`)の引数に指定できる `’fields’ => ‘ids’` です。
具体的なコードと意味
‘post’,
‘posts_per_page’ => 1000, // 1000件という大量データ
‘fields’ => ‘ids’, // ★ここが最大のポイント!
‘no_found_rows’ => true, // ページネーション用の総数計算をスキップしてさらに高速化
) );
$post_ids = $query->posts; // これの中身は [ 1253, 1250, 1248, … ] のような整数の配列になります
foreach ( $post_ids as $post_id ) {
// 必要な処理(例:カスタムフィールドの更新や、別の処理への引き渡し)
// この時点では WP_Post オブジェクトはメモリ上に存在しません!
}
何が起きているのか?
`’fields’ => ‘ids’` を指定すると、MySQLに対して発行されるSQLクエリは、以下のように劇的に変化します。
- 通常時 (`get_posts`等): `SELECT FROM wp_posts WHERE …`
- `fields => ‘ids’` 時: `SELECT wp_posts.ID FROM wp_posts WHERE …`
取得するカラムが `ID` だけになり、さらに PHP 側で `WP_Post` オブジェクトのインスタンス化が一切行われません。 返ってくるのは、ただの整数の配列(`int`型の羅列)です。これによるメモリ削減効果は、データ量が大きくなればなるほど圧倒的な差となって現れます。
—
3. 徹底比較:メモリ消費量と使いどころの判断基準
ここで、初学者が陥りやすいポイントや、それぞれのメリット・デメリットを整理してみましょう。
| 比較項目 | `get_posts()` (デフォルト) | `WP_Query` + `fields => ‘ids’` |
| :— | :— | :— |
| 返り値のデータ構造 | `WP_Post` オブジェクトの配列 | 記事ID(整数)の配列 |
| メモリ消費量 | 高 (データ量に比例して増大) | 極めて低 (IDの配列のみ) |
| 向いているシーン | 記事のタイトル、本文、アイキャッチなどを画面に表示したいとき | 大量データのバッチ処理、IDだけを元に別処理を行いたいとき、キャッシュのキー生成など |
| 注意点 | 大量取得時にメモリ制限に引っかかりやすい | 実際のタイトルや本文を使うには、後から個別でロードするか追加のクエリが必要 |
陥りやすい文法エラー・アンチパターン
よくあるミスとして、`fields => ‘ids’` を指定したにもかかわらず、ループ内でうっかりオブジェクトのプロパティを呼び出してしまうケースがあります。
// 【やってはいけないアンチパターン】
$query = new WP_Query( array(
‘posts_per_page’ => 10,
‘fields’ => ‘ids’,
) );
foreach ( $query->posts as $post ) {
// エラーまたは意図しない挙動になります!
// $post はオブジェクトではなく単なる「整数(ID)」だからです。
echo $post->post_title;
}
正しくは、取得したIDを使って必要な情報を扱うか、あるいは以下のように記述します。
// 【正しい書き方】
foreach ( $query->posts as $post_id ) {
// IDだけを使って何か処理をする場合
echo ‘記事ID: ‘ . $post_id . ‘
‘;
// もし特定の記事のタイトルがどうしても必要になったら、get_post() で都度取得する
// $post_obj = get_post( $post_id );
// echo $post_obj->post_title;
}
—
先輩エンジニアからの実践アドバイス:キャッシュ戦略との組み合わせ
現場で大規模なWordPressサイトを構築する際、私たちはただクエリを最適化するだけでなく、「オブジェクトキャッシュ(MemcachedやRedis)」や、WordPress標準のトランジェントAPIを組み合わせてデータベースへの負荷そのものをゼロに近づける設計を行います。
例えば、「最新の投稿ID 100件のリスト」を `fields => ‘ids’` で取得し、そのID配列自体を一時キャッシュに保存しておけば、データベースへのヒット数を劇的に減らすことができます。
100,
‘fields’ => ‘ids’,
‘no_found_rows’ => true,
));
$post_ids = $query->posts;
// 1時間キャッシュする
set_transient( ‘my_heavy_post_ids’, $post_ids, HOUR_IN_SECONDS );
}
// キャッシュされたIDリストを使って処理を実行
foreach ( $post_ids as $id ) {
// 高速な処理…
}
このように、「どのデータを、どのような形で、どれだけの量メモリに載せるべきか」を意識できるようになると、WordPressの挙動が手に取るように分かるようになり、開発が何倍も楽しくなりますよ。
今回の内容をしっかり咀嚼して、ぜひご自身の開発現場や趣味のサイトで試してみてくださいね。あなたのWordPressライフが、より快適で素晴らしいものになることを応援しています!