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

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

【25卒向け】AI×バーチャル面接の募集を開始いたしました!

【25卒向け】AI×バーチャル面接の募集を開始いたしました!

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

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

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

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

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

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

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

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

【低コスト】Wasabi オブジェクトストレージ 構築・運用サービス

【低コスト】Wasabi オブジェクトストレージ 構築・運用サービス

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

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

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

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

【中国現地企業に対応】中国クラウド / サーバー構築・運用保守

【中国現地企業に対応】中国クラウド / サーバー構築・運用保守

【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’)したらメモリが足りなくなった【解決】 | 株式会社ビヨンド

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

【2024.6.30 CentOS サポート終了】CentOS サーバー移行ソリューション

【25卒向け】AI×バーチャル面接の募集を開始いたしました!

【25卒向け】AI×バーチャル面接の募集を開始いたしました!

【大阪 / 横浜】インフラエンジニア・サーバーサイドエンジニア 積極採用中!

【大阪 / 横浜】インフラエンジニア・サーバーサイドエンジニア 積極採用中!

この記事をかいた人

About the author

長谷竜弥

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

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

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

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