【大阪 / 横浜 / 徳島】インフラ / サーバーサイドエンジニア募集中!

【大阪 / 横浜 / 徳島】インフラ / サーバーサイドエンジニア募集中!

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

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

【CentOS 後継】AlmaLinux OS サーバー構築・移行サービス

【CentOS 後継】AlmaLinux OS サーバー構築・移行サービス

【WordPress 専用】クラウドサーバー『ウェブスピード』

【WordPress 専用】クラウドサーバー『ウェブスピード』

【格安】Webサイト セキュリティ自動診断「クイックスキャナー」

【格安】Webサイト セキュリティ自動診断「クイックスキャナー」

【予約システム開発】EDISONE カスタマイズ開発サービス

【予約システム開発】EDISONE カスタマイズ開発サービス

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

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

【200ヶ国以上に対応】グローバル eSIM「ビヨンドSIM」

【200ヶ国以上に対応】グローバル eSIM「ビヨンドSIM」

【中国への旅行・出張・駐在なら】中国SIMサービス「チョコSIM」

【中国への旅行・出張・駐在なら】中国SIMサービス「チョコSIM」

【グローバル専用サービス】北米・中国でも、ビヨンドのMSP

【グローバル専用サービス】北米・中国でも、ビヨンドのMSP

【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文を使うよりも断然偉いですよね。
勉強になりました!

以上です。

この記事がお役に立てば【 いいね 】のご協力をお願いいたします!
3
読み込み中...
3 票, 平均: 1.00 / 13
4,558
X facebook はてなブックマーク pocket
【2025.6.30 Amazon Linux 2 サポート終了】Amazon Linux サーバー移行ソリューション

【2025.6.30 Amazon Linux 2 サポート終了】Amazon Linux サーバー移行ソリューション

この記事をかいた人

About the author

長谷竜弥

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

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

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

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