5丁目通信(仮称)

とある5丁目で活動する還暦を過ぎたWebプログラマーの覚え書きです。それとかかってくる迷惑電話や、家業のアパート経営について。

CakePHPのpaginateの最適化の話し

ページングが簡単にできてしまうCakePHPのpaginateはとても便利です。パラメーターをちょっと設定してあげるだけなので、誰でも使いたくなるはず。

しかし、このpaginateには、大きな落とし穴があります。いくつものアソシエーションを設定されているモデルに対してpaginateを使うと、とても遅いのです。

これはpaginateだけではなくfindAllでも言えること。何も考えずに使うと、結果が返ってこないのです。

デバッグレベルを3にするとわかるのですが、大量にSQLが生成されます。この辺りをきちんとチューニングしてあげないといけません。

paginateの最適化を調べましたが、なかなか検索にひっかかりません。仕方ないので、試行錯誤。結局は以下の通り。

必要のないアソシエーションは実行する前に削除しておく。モデルクラスで最初に$hasManyを定義しますが、このままですと勝手にそのモデルへの抽出のためのSQLを発行してくれます。paginateのfieldsオプションに、抽出したい項目を並べておけば、それだけをSQL一つで抽出してくれるかと思っていましたが、これは大間違え。$hasManyに定義されているモデルに対して1レコードづつ改めてSQLを生成します。

あと、アソシエーションが3つになると、例えばA->B->Cと各モデルがhasMany,belongsToのアソシエーションを定義されているとすると、Aに対してpaginateをすると、A->Bで参照されたSQLを発行して、その後各レコードでCを参照するSQLが発行されてしまいます。したがって、Cがあまり大きなテーブルではなくて、ほとんど更新がないようなテーブルだと、データを配列に格納して参照させたほうがいいかもしれません。

とにかく、CakePHPのpaginateやfindAllは、余計なSQLを発行してくれます。いかに無駄なSQLを削除するかがパフォーマンスの分かれ目です。

今回、以上の方法でCakePHPから発行しているSQLの数を一桁以上減らすことで、paginateのパフォーマンスをあげました。一番のCakePHPのチューニング方法は、core.phpでデバッグレベルを3にして表示されるデバッグ情報のSQLダンプを見ながら調整していくことをお勧めします。

This website stores cookies on your computer. These cookies are used to provide a more personalized experience and to track your whereabouts around our website in compliance with the European General Data Protection Regulation. If you decide to to opt-out of any future tracking, a cookie will be setup in your browser to remember this choice for one year.

Accept or Deny