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で何回かに分け処理を行う場合は使ってみてはどうでしょう。