【Laravel】メモリ不足で悩むあなたへ Eloquent Chunkの薦め

2021年8月5日

こんにちは。今回はEloquentORMで数万〜数十万レコードの大量データを効率よく処理する方法について考えていきます。

Eloquentで大量データを扱う場合に注意しなければならないのが「メモリ使用量」です。一度に数十万のレコードを取得してしまうと、メモリを多く消費してしまい、php.iniで設定したメモリ上限(memory_limit)を超えるとエラーとなるからです。

メモリ使用量の問題を解決するための手段としてLaravelにはChunkという機能が提供されています。本記事ではChunkについて解説していきます。

Chunkとは

Chunkとはデータを分割して取得する機能です。getやall メソッドが一括でデータを取得するのに対してchunkは指定した件数ずつデータを取得します。例えば1000件のデータを5回に分けて200件ずつ取得したりできます。この場合、サーバーは200件分のメモリしか確保しなくて良くなるのでメモリ使用量の節約ができるというわけです。

Chunkを体験

早速chunkを体験してみましょう。

3万件のデータを用意しchunkで取得してみます。この時、1度に取得するデータ件数を何パターンか試して、メモリ使用量がどの程度変化するかを計測したいと思います。

実験を始める前にchunkのコードを解説します。Eloquentのモデルが持つchunkメソッドを使用します。第一引数には1度に取得するデータの件数をセットします。chunkはこの件数に合わせてデータの取得を繰り返してくれます。第2引数はクロージャの形式で指定します。chunkで取得したコレクションが引数で渡ってきますので、クロージャの中で取得したコレクションを処理できます。

    public function index () {
        // 1000件ずつデータを取得
	      Post::chunk(1000, function ($posts){
			      // この中で取得したコレクションを処理する
		    });
	 }

メモリ使用量の変化を体感するため、一度に取得する件数を1000, 5000, 10000,30000の3パターン試してみたいと思います。以下、実行結果を表にまとめてみました。

1度に取得するデータ件数メモリ使用量
1,0006.1MB
5,00013.7MB
10,00021.5MB
30,000 (全件)66.19MB

30,000件と1,000件でかなり差が生まれました。メモリ使用率の低減にはかなりの効果があることがわかりました。これだけの効果があるので大量データ操作の場合は積極的に使用したい機能ですね。

この結果だけ見るとかなり万能な機能に思えるのですが、注意すべきポイントもあります。それば実行速度が遅くなるという点です。一度に取得する件数を減らした場合、クエリを発行する回数は増えるため、パフォーマンスには影響を与える可能性があります。何度もSQLを実行することになるので当然ですね。実行速度とメモリ効率は常に同時に考慮し、バランスの良い点を見つけ出すことが重要だと思います。

いかがでしょうか。chunkは非常に強力な機能なので、使い方を覚えて是非使っていただきたいです。

Laravel

Posted by kobainmac