CakePHP3のクエリービルダーについて
PHPのフレームワークとして有名なCakephpの3で使える処理速度改善方法の中で最近知ったクエリービルダーについて一つお話しします
クエリーオブジェクトのforeach処理
CakePHP3でクエリービルダーを使用してクエリーオブジェクトの形でDBからデータを取得します。
その際の取得形式で処理時間に差を作ることができます。
例としてArtivlesテーブルからレコードを全件取得するソースを2パターン書いてみる。
パターン1
$articles = $this->Articles->find();
foreach ($articles as $article) {} // 処理実行1
パターン2
$articles = $this->Articles->find()->toArray();
foreach ($articles as $article) {} // 処理実行1
今回は実行時間の差を見やすくするためレコードを1000件用意してみた。
レコード取得の実行時間は以下の通り
パターン1 0.0885570049秒
パターン2 0.0890669823秒
対して違いは見れない。
続いて下記のソースをforeachの数を1から10にして実行してみる
foreach ($articles as $article) {} // 処理実行1
foreach ($articles as $article) {} // 処理実行2
foreach ($articles as $article) {} // 処理実行3
foreach ($articles as $article) {} // 処理実行4
foreach ($articles as $article) {} // 処理実行5
foreach ($articles as $article) {} // 処理実行6
foreach ($articles as $article) {} // 処理実行7
foreach ($articles as $article) {} // 処理実行8
foreach ($articles as $article) {} // 処理実行9
foreach ($articles as $article) {} // 処理実行10
レコード取得の実行時間は以下の通り
パターン1 0.1360001564秒
パターン2 0.0915861130秒
0.04秒の違いが見れた。
なぜ違いが出たかというとパターン1
$this->Articles->find();
上記時点ではまだSQL文が流れておらずクエリー形式で取得しforeachに入るとイテレートされ実行される
パターン2では
$articles = $this->Articles->find()->toArray();
上記時点でSQL文が流れてクエリーオブジェクトの形式で取得しforeachにはその取得したクエリーオブジェクトで実行している。
パターン2は最初に取得したものをforeachを実行しているのに対してパターン1はforeachのたびにイテレートしているため時間がかかるみたい。
今回は1000件で行いましたが件数が増えれば増えるほどイテレートに時間がかかりますので目に見えて遅くなります。
たとえforeachが2つしかなくとも数万~数十万件のデータを扱った場合はtoArrayを使った方が断然早いです(私はDBデータから複数CSV出力する際に確認しました)
必ずしもクエリーオブジェクトからとるべきとは言えないが、一度取得したデータをforeachで何回かに分け処理を行う場合は使ってみてはどうでしょう。