[Laravel] DB::insert()実行時のメモリリークについて
先日LaravelにてCSVからデータベースにデータを移行するバッチを実装していたところ、実行時にメモリ不足となりkillされてしまいました。
状況
CSVを取り込みDBに格納する際、こちらのページを参考にし以下のとおり1行づつ読み取ることでメモリを節約しています。
$file = new \SplFileObject(storage_path('app/data_migration/sample.csv')); $file->setFlags( \SplFileObject::READ_CSV | \SplFileObject::READ_AHEAD | \SplFileObject::SKIP_EMPTY | \SplFileObject::DROP_NEW_LINE ); $records = array(); foreach ($file as $i => $row) { if($i===0) { foreach($row as $j => $col) $colbook[$j] = $col; continue; } $line = array(); foreach($colbook as $j=>$col) $line[$colbook[$j]] = @$row[$j]; DB::table("test")->insert($line); }
この処理を行う際、memory_get_usege()を使用してメモリ使用量を監視してみたのですがforeachが回るたびに徐々に増えていき、やがてメモリ上限を超えタスクが終了されてしまいました。
しかし、DB::insert()の部分を以下のようにqueryを書いて実行するとメモリは上がらず一定でしたのでLaravel自体の問題かと思っています。
$columns = implode(',', array_keys($line)); $values = implode(',', $line); $query = "insert into test (" . $columns . ") values (" . $values . ")"; DB::connection()->getPdo()->query($query);
試したこと
- DB::disableQueryLog()を記述
- デバッグライブラリを確認しましたが特別な物は入れていませんでした。(デフォルトのまま)
- バルクインサート(当然変わりません...)
上記の上から2つは海外の掲示板を見た中で有力そうな解決策でした。
disableQueryLog()に関しては有力ではあったのですが何も変わらずでした。こちらデフォルトでdisableのようで、逆にenableQueryLog()を記述したところメモリ使用量がさらに上がりました。
状況からしてクエリビルダ関連だとは思うのでLaravel内部の問題だとは思うのですが...。
丸1日潰してしまったので皆様にご教授いただきたいと思っております。
よろしくお願いいたします。
追記
// バージョン情報 Laravel:6.x PHP:7.4 PostgreSQL:11
さらに追記
説明不足ですみません。今回はメモリ不足を解消するためにメモリを上げるのではなく、
根本的にDB::insertの使用で上がってしまうメモリ使用量をどうにかしたいと考えております...。
CSVの処理に関わらずinsertの処理の部分で起きているので
Laravelのバグなのか、Laravel内部で何をやっているのか等突き止めたいです。
回答3件
あなたの回答
tips
プレビュー