【導入実績300社以上】AWS 構築・運用保守サービス

【導入実績300社以上】AWS 構築・運用保守サービス

【サーバー管理不要】WordPress専用クラウド『WebSpeed』

【サーバー管理不要】WordPress専用クラウド『WebSpeed』

【100URLの登録が0円】Webサイト監視サービス『Appmill』

【100URLの登録が0円】Webサイト監視サービス『Appmill』

【コミュニケーションアプリ開発】LINE アプリ開発サービス

【コミュニケーションアプリ開発】LINE アプリ開発サービス

【ECサイト構築】Shopify カスタムアプリ開発サービス

【ECサイト構築】Shopify カスタムアプリ開発サービス

【音声アプリ開発】Twilio アプリ開発サービス

【音声アプリ開発】Twilio アプリ開発サービス

【グローバル対応】北米リージョン・クラウド / サーバー サポート

【グローバル対応】北米リージョン・クラウド / サーバー サポート

【CPU】AMD EPYC 技術検証(PoC)サービス

【CPU】AMD EPYC 技術検証(PoC)サービス

【Webシステム / サービス開発】SAKARAKU Lab(セカラクラボ)

【Webシステム / サービス開発】SAKARAKU Lab(セカラクラボ)

【取材記事】サーバー系企業ビヨンドが サーバーサイドエンジニアを募集中

【取材記事】サーバー系企業ビヨンドが サーバーサイドエンジニアを募集中

【対談記事】「やっぱクラウド移設っていいですよね」マイネット × ビヨンド エンジニア対談

【対談記事】「やっぱクラウド移設っていいですよね」マイネット × ビヨンド エンジニア対談

【YouTube】ビヨンド公式チャンネル「びよまるチャンネル」

【YouTube】ビヨンド公式チャンネル「びよまるチャンネル」

CakePHPで大量のデータをfind(‘all’)したらメモリが足りなくなった【解決】

開発チームの長谷です。

前回の記事で、CakePHPでメモリエラーを発生させずに大量のデータをfind(‘all’)する方法を書かせていただきましたが、
その記事の内容で色々と社内でご指摘を受けましたので、
今回は前回の内容のフィードバックを書かせていただきます。

ですので、前回の記事はペーペープログラマーの戯言としてご覧になられると幸いでございます。。。

現在のコード

$data = $this->Model->find('all');

// 何らかの処理
.........

query()を使用するのは×

前回の記事より

query()で取得する方がfind(‘all’)で取得するよりも処理が軽くなるらしいです。
なので、findで取得してきていたものをquery()で取得するように修正。

これは間違いです。

そもそも、queryメソッドは複雑なクエリを実行するときに使うものであって、
使う場合はサニタイズとかバリデーションする必要があるので、安易に使わない方が良いらしいです。
そもそも、findを使うようにした方がフレームワークの機能を有効に使えて楽なので、
queryメソッドを使う必要は今回は全くありませんでした。。

for文でループするのではなく
while文でループしながらデータを取得する方が偉い

前回はforループを使ってデータを分割して取得してました。

前回のコード

// データの件数を取得する
$count = $this->Model->find('count');

// 5000件ずつデータを取得するようにする
$limit = 5000;

// ループする回数({データ件数 ÷ 1回の取得件数}の端数を切り上げた数)
$loop  = ceil($count / $limit);

for ($i = 0; $i < $loop; $i++){
	// オフセット
	$offset = $limit * $i;
	
	$data = $this->Model->query("select * from hogehoge as limit {$limit} offset {$offset};", $cachequeries = false);
	
	// 何らかの処理
	.........

}

この方法でも間違ってはいないのですが、

実はwhile文を使って取得する方が方法として偉いということが分かりました。
while文だとcountを取る必要もないし、loop回数を計算する必要もありません。
あとquery()ではなくfind('all')ですね。。。

てことでwhile文で書き直してみました。

書き直したコード

// 5000件ずつデータを取得するようにする
$limit = 5000;

$params = array('limit' => $limit, 'offset' => 0);

while ($data = $this->Model->find('all', $params)){
	// 何らかの処理
	$params['offset']+= $limit;
}

こちらの方が無駄な処理がないので、for文を使うよりも断然偉いですよね。
勉強になりました!

以上です。

この記事がお役に立てば【 いいね 】のご協力をお願いいたします!
0
読み込み中...
0 票, 平均: 0.00 / 10
2,509
facebook twitter はてなブックマーク

この記事をかいた人

About the author

長谷竜弥

新卒にて株式会社ビヨンドに入社。

Webシステム開発(Webサービス・デジタルコンテンツ・業務管理システム などのブラウザで動くサービス、システムの開発)や、ゲームAPI(アプリゲームとの通信部分のプログラム開発)を行っている。

また、Shopify のプライベート / カスタムアプリの開発も行っている。

元々は大阪オフィスに勤めていたが、2019年に横浜オフィスに転勤。
趣味は野球 / カラオケ / アニメ