Blog

query_postsはWordPressが重くなる原因

Posted by admin at 7:01 日時 2013/09/24

今回は技術話ではなく雑談レベルのネタです。WordBench Kobeで発表したこれからのpre_get_postsの話をしようのスライドでは、query_posts() が、WordPressが一度投稿を取得した後に再度条件を変えて取得しなおしていることが問題だ、と指摘しました。ところが、どうも2回呼び出しているという以上に、query_posts() はそれ単体でもWordPressを重くする原因らしいぞ、という情報を入手しました。

詳しくはコアデベロッパーのnacinのスライドに書いてあります。


実のところ、query_posts() は通常、これ単体で大きく分けて4回データベースにアクセスします。

  1. SQL_CALC_FOUND_ROWS オプションを付けて投稿データを取得する
  2. SELECT FOUND_ROWS() クエリを発行し、条件に該当する投稿の件数の総数を取得する
  3. 取得した投稿のメタデータ(カスタムフィールドのデータ)を取得してキャッシュする
  4. 取得した投稿のターム(カテゴリー、タグなどのタクソノミーのデータ)を取得してキャッシュする

“SQL_CALC_FOUND_ROWS” でググると、予測候補に “SQL_CALC_FOUND_ROWS 遅い” とか “SQL_CALC_FOUND_ROWS 速度” とか出てきます。COUNT文よりは速いのですが、どうも常に高速というわけではなさそうですね。というか重くて困ってる人がちらほら。件数が増えると影響が出てくるようです。こんな重いと評判のオプションが、query_posts() を使うとデフォルトでくっついてくるわけですね。

これは何のオプションかというと、SQL文の条件に合致するデータの総数を取得するためのオプションです。query_posts(‘post_per_page=5’) の様に件数を指定したとしても、必ず全件のデータを取得します。なぜかというと、これはページ送りのためです。全部で何件のデータがあるのかを取得しないと、次のページがあるのか無いのかが判断できません。でも、ページ送りが必要なのはページのメインクエリーだけのはず。例えば新着情報を5件サイドバーに表示するのに、ページ送りは要りませんよね。そういうサブクエリーであっても、query_posts()を使ってしまうと、わざわざ全件のデータを取得することで重くなるというわけです。COUNT文よりは速いとはいえ、要らないものがついてることには変わりない。

実はこれは query_posts() の裏で動いているWP_Queryクラスの初期設定です。WP_Queryクラスにはこの SQL_CALC_FOUND_ROWS オプションをオフにできる ‘no_found_rows’ オプションが用意されています。初期値はfalseですがこれをtrueに変えることで SQL_CALC_FOUND_ROWS を付けずに高速化することができます。

$args = array(  	'post_per_page' => 5,  	'cat' => 1,  	'no_found_rows' => true  );  $get_posts = new WP_Query($args);

でもちょっとややこしいし、こんなオプションつけ忘れそうですよね。そこで get_posts() の出番です。get_posts() 関数はこの no_found_rows オプションがデフォルトでtrueになっています。サブクエリーの発行には query_posts() をやめて get_posts() を使うようにしましょう!

さらに、取得した投稿データのタクソノミーを使わないことがはっきりしている場合は ‘update_post_term_cache’ オプションを、取得した投稿データのカスタムフィールドを使わない場合は ‘update_post_meta_cache’ オプションを、それぞれ false にすると上記の 3. 4. の処理が行われなくなり、さらに高速化するそうです。でもこれは上級者向けかもしれませんね。さすがにそこまで考えて作るのは面倒だし。

$args = array(  	'post_per_page' => 5,  	'cat' => 1,  	'no_found_rows' => true,  	'update_post_term_cache' => false,  	'update_post_meta_cache' => false  );  $get_posts = new WP_Query($args);

参考記事

WordPressは記事の件数が多くなると重くなるのか? – この記事が書かれた2011年よりはWP_Queryも高速化が図られている模様。

余談

本格ビジネスサイトを作りながら学ぶ WordPressの教科書2

  • 著者/訳者:プライム・ストラテジー株式会社
  • 出版社:SBクリエイティブ( 2013-08-29 )
  • 大型本:488 ページ
  • ISBN-10 : 4797370963
  • ISBN-13 : 9784797370966
  • 定価:¥ 3,218

読んでないけど聞いた話だと教科書2ではあえてquery_postsを使っているらしい。前に記事にも書いたけど、確かにget_postsもWP_Queryインスタンスを使う方法も微妙に使いづらい。初心者に取っては同じようなことをしているのに書き方が微妙に違うというのは、混乱する。なので、最初はquery_postsで統一して説明するという判断はありだと思う。そして、WordPressでの開発に慣れたらWP_Queryのみを使うという流れの方がいいかもしれない。今後のコアコードの改善に期待する。

余談2

結局、SQL_CALC_FOUND_ROWSがどういう条件の時にパフォーマンスを害するのかは、ちょっと調べた限りでは分からなかったが、クエリによる(使わない方がインデックスが効いて速いときも)という書き込みもあったけど、専門じゃないのでさっぱり。


Share this entry