こんにちは!WordPressの裏側の仕組みって、覗いてみるとすごく奥が深くて面白いですよね。他の言語やフレームワークからWordPressの世界に入ってきた開発者なら、「たった一つの引数を変えただけで、なぜデータベースが重くなるんだろう?」と疑問に思ったことがあるかもしれません。
今回は、初心者の方が一番最初にハマりやすい、`WP_Query`の`orderby`で`post_date`以外を指定したときに起こるパフォーマンス低下の仕組みについて、データベースの内部挙動を覗きながら分かりやすく解説していきますね。
ここをクリアすれば、WordPressのデータベース構造とクエリ最適化の基本はバッチリマスターできますよ!一緒にそのメカニズムを紐解いていきましょう。
—
1. そもそも `WP_Query` の裏側で何が起きているのか?
WordPressの記事データは、MySQLというリレーショナルデータベースの `wp_posts` という巨大なテーブルに保存されています。
私たちがPHPで `new WP_Query()` を実行すると、WordPressは内部でよしなにSQLクエリを組み立て、データベースへ投げつけて結果を取得しています。このとき、データベースがデータをどのように探して並べ替えるかが、サイトの表示速度(パフォーマンス)を大きく左右するんです。
まずは、デフォルトの状態を見てみましょう。
// 例1:王道の最新記事取得(post_date順)
$query = new WP_Query([
‘post_type’ => ‘post’,
‘posts_per_page’ => 10,
‘orderby’ => ‘date’, // 省略してもデフォルトでpost_date順になります
‘order’ => ‘DESC’,
]);
この「投稿日(`post_date`)の新しい順」で取得するとき、MySQLはめちゃくちゃ高速に動作します。なぜなら、データベースの設計図(インデックス)に秘密があるからです。
—
2. インデックス(索引)の正体と「図解的イメージ」
データベースのインデックスは、よく本の後ろについている「索引(さくいん)」に例えられます。
厚いプログラミングの辞書から「WordPress」という単語を探すとき、1ページ目から順番にめくっていく(これをデータベース用語で「フルテーブルスキャン:全表走査」と言います)と、すごく時間がかかりますよね。でも、巻末の索引で「わ行」のページ番号をパッと見れば、一瞬でお目当てのページにたどり着けます。
WordPressの `wp_posts` テーブルには、最初からいくつかの「索引」が用意されています。その代表が `post_date`(投稿日) です。
【wp_postsテーブルのイメージ(post_dateインデックスが効いている状態)】
[索引: post_date順] ──> 2023-10-01 ──> 2023-09-15 ──> 2023-08-20 …
↓ ↓ ↓
[実際の行] [実際の行] [実際の行]
`post_date` でソートしてね、とお願いされたMySQLは、あらかじめ綺麗に並べられた「索引」を上から順番に10個拾うだけなので、一瞬で処理を終えられます。
—
3. 「Using filesort(ファイルソート)」の恐怖
それでは、初心者のうちはやりがちな、こんなコードを書いてみたとします。
// 例2:カスタムフィールドの値(例: 閲覧数 ‘post_views’)で並び替えたい!
$query = new WP_Query([
‘post_type’ => ‘post’,
‘posts_per_page’ => 10,
‘meta_key’ => ‘post_views’,
‘orderby’ => ‘meta_value_num’, // 数値としてメタデータの大き順に並び替え
‘order’ => ‘DESC’,
]);
一見、何の問題もなさそうな美しいコードに見えますよね。しかし、データベースの内部で何が起きているかを知ると、少しゾッとするはずです。
データベース内部の悲劇
1. 索引がない!:`wp_posts` テーブル(あるいは関連する `wp_postmeta` テーブル)には、デフォルトでは `post_views` というカスタムフィールドの順に並んだ「索引」なんてありません。
2. とりあえず全部持ってくる:MySQLは、条件に合うデータをディスクからすべて引っ張り出してきます(数万件、数十万件あるかもしれません)。
3. 机の上で並べ替える(Filesort):引っ張り出してきた大量のデータを、一時的な作業スペース(メモリやディスク上のファイル)にドサッと広げ、手作業で大きい順に並べ替えます。これが `Using filesort` と呼ばれる現象です。
【Using filesort のイメージ】
[ディスクから全データを取得]
↓ (山積みのデータ)
[一時エリアに広げる] ──> 【必死に並べ替え作業(Filesort)!】 ──> やっと上位10件を取り出す
これが、記事数が数千件を超えてきたあたりからサイトが急に重くなり、サーバーのCPU使用率が跳ね上がる最大の原因になります。
—
4. 陥りやすい文法エラーとアンチパターン
ここで、開発現場でよく見かける「やってしまいがちな失敗」をいくつか挙げておきますね。
① `meta_value` の型指定ミス
文字列としてソートする `meta_value` と、数値としてソートする `meta_value_num` を間違えると、意図しない並び順になるだけでなく、パフォーマンスの無駄な消費に繋がります。数値なら必ず `meta_value_num` を使いましょう。
② 大量の投稿に対してランダムソート (`orderby => ‘rand’`) を使う
// 絶対にやってはいけないアンチパターン
$query = new WP_Query([
‘posts_per_page’ => 5,
‘orderby’ => ‘rand’, // ランダム表示
]);
これ、全件に対して毎回ランダムな数値を割り振って `Using filesort` を実行するため、データベースを完全に破壊しかねないほどの超重い処理になります。データが増えると確実にサイトがダウンするので、ランダム表示は別の軽量なアプローチ(PHP側でシャッフルするなど)を検討しましょう。
—
5. では、どうやってクエリを最適化すべきか?
「じゃあ、日付順以外の並び替えは諦めなきゃいけないの?」いいえ、そんなことはありません!プロのエンジニアは次のようなアプローチでこの問題を華麗にクリアします。
解決策:あらかじめ「インデックスが効く状態」を作る、またはキャッシュする
1. カスタムインデックスの追加:データベースに直接手を入れて、頻繁にソートや検索に使うカラム(カスタムテーブルやメタキーなど)にカスタムインデックスを貼る(中・上級者向け)。
2. Transient API などのオブジェクトキャッシュの活用:重いクエリの結果を一定時間キャッシュし、毎回データベースに走らせないようにする。
3. 構造の見直し:本当にそのソートがリアルタイムで必要か?を見直し、例えば「日別・週別・月別の集計データ」は別テーブルやオプションに保存しておく。
例えば、Transient APIを使って重いクエリ結果をキャッシュする基本形は次のようになります。
// キャッシュのキーを定義
$cache_key = ‘popular_posts_query_cache’;
$posts = get_transient( $cache_key );
if ( false === $posts ) {
// キャッシュがない場合のみ、重いクエリを実行
$query = new WP_Query([
‘post_type’ => ‘post’,
‘posts_per_page’ => 5,
‘meta_key’ => ‘post_views’,
‘orderby’ => ‘meta_value_num’,
‘order’ => ‘DESC’,
]);
$posts = $query->posts;
// 1時間(3600秒)キャッシュを保存
set_transient( $cache_key, $posts, HOUR_IN_SECONDS );
}
// 取得した投稿データを使ってループを回す
foreach ( $posts as $post ) {
setup_postdata( $post );
// 描画処理
}
wp_reset_postdata();
これなら、2回目以降のアクセスはデータベースへの負荷が「ゼロ」になり、サイトは驚くほど軽快に動作します!
—
まとめ
- `post_date` 以外の項目で `orderby` を指定すると、MySQL内部でインデックスが使えず、`Using filesort`(全件取得からのメモリ内ソート)が発生しやすい。
- データ量が増えると、これがサーバーの重さやパフォーマンス低下のダイレクトな原因になる。
- 大量データを扱うクエリには、型を正しく指定する、ランダムソートを避ける、そして Transient API などのキャッシュ戦略を組み合わせる ことが、プロのフルスタックエンジニアとしての必須スキル!
「なぜこのコードを書くとデータベースが苦しむのか?」という裏側のストーリーがイメージできるようになると、コードを書くのがもっと楽しく、そして美しくなりますよ。
今回の知見をあなたの開発現場にぜひ活かしてみてくださいね。WordPressの海を、一緒にスマートに泳ぎ切っていきましょう!