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

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

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

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

【圧倒的 低コスト】Oracle Cloud 構築・運用保守・監視サービス

【圧倒的 低コスト】Oracle Cloud 構築・運用保守・監視サービス

【WordPress専用】高速 クラウド / サーバー『WebSpeed』

【WordPress専用】高速 クラウド / サーバー『WebSpeed』

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

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

【次世代】ゲーム専用データ分析エンジン『ThinkingEngine』

【次世代】ゲーム専用データ分析エンジン『ThinkingEngine』

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

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

【SNSアプリ開発】LINE カスタムアプリ開発サービス

【SNSアプリ開発】LINE カスタムアプリ開発サービス

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

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

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

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

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

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

【取材記事】サーバーサイド・バックエンドエンジニアを募集中

【取材記事】サーバーサイド・バックエンドエンジニアを募集中

【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
5,826
facebook twitter はてなブックマーク
【大阪 / 横浜】インフラエンジニア / サーバーサイドエンジニア 積極採用中!

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

この記事をかいた人

About the author

長谷竜弥

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

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

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

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