【導入実績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で10万件近くあるデータをfind(‘all’)で取得しようとしたらメモリが足りなくなって、
以下のエラーが出てしまいました。。

Allowed memory size of 134217728 bytes exhausted

そこで、メモリを抑えて10万行近くのデータを取ってこれるようにする方法を色々と調べてみました。

現在のコード

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

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

query()を使用する

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

$data = $this->Model->query("SELECT * FROM hogehoge;");

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

結果

気持ち処理が軽くなった気がしましたが、
find('all')して取得した時と変わらず、メモリが足らずエラーが出てしまいました。

query() のキャッシュを無効にする

公式を見たところ、query()にはデフォルトでクエリをキャッシュする仕組みになっているようです。
このクエリをキャッシュするのを無効にするためには、query($query, $cachequeries = false)
というように第2引数に false を指定することで無効にすることができます。
てことで、query() の第2引数に false を指定してみました。

$data = $this->Model->query("SELECT * FROM hogehoge;", $cachequeries = false);

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

結果

結論としては特に変化はありませんでした。。

ループを使ってデータを分割しながら取得する

そもそも上の方法だと、10万件のデータを一気に取得していることには変わりがないので、
メモリが足らなくなるのは当然でした。
ということでlimit,offsetを駆使してループ処理でデータを分割して取得するようにしてみました。

// データの件数を取得する
$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);
	
	// 何らかの処理
	.........

}

結果

素晴らしい結果となりました。
メモリエラーも出ず、データもちゃんと取得できていましたのでこれで問題ないですね!!

てことで、もし同じ現象で困っている方がいらっしゃいましたら参考にしていただければ幸いです。

以上です。

しかし、この方法では…
続きはこちらをご覧ください。
CakePHPで大量のデータをfind(‘all’)したらメモリが足りなくなった【解決】 | 株式会社ビヨンド

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

この記事をかいた人

About the author

長谷竜弥

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

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

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

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