質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

3回答

9100閲覧

[Laravel] DB::insert()実行時のメモリリークについて

hk206

総合スコア20

CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

2クリップ

投稿2020/05/21 13:21

編集2020/06/02 01:26

[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内部で何をやっているのか等突き止めたいです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mikkame

2020/05/31 13:01

laravelのバージョンも記載していただいた方が良いかと思います
hk206

2020/05/31 13:11

すみません。バージョン情報を記載し忘れていました。 ご指摘ありがとうございます。
mikkame

2020/05/31 13:14

マイナー・パッチまでわかりますか? 以前、私がバグを踏んだ時はパッチで修正されていたことがありました。
hk206

2020/05/31 13:30

6.11.0でした。 そういえばと思い、自分のローカルのプロジェクトでinsert文を何千と実行させてみたところメモリが一定でした...。 バージョンを確認すると6.18.10でした...。 パッチ修正の可能性がありますね。明日にならないと試せないのですが、バージョンをいじってみます!
hk206

2020/06/02 05:49 編集

問題のプロジェクトでバージョンを更新しましたがやはり現象変わらずでした...。 >>自分のローカルのプロジェクトでinsert文を何千と実行させてみたところメモリが一定でした。 これはやはり正しいです。
guest

回答3

0

php

1 $rows = new \SplFileObject(storage_path('app/data_migration/sample.csv')); 2 3 $rows->setFlags( 4 \SplFileObject::READ_CSV | 5 \SplFileObject::READ_AHEAD | 6 \SplFileObject::SKIP_EMPTY | 7 \SplFileObject::DROP_NEW_LINE 8 ); 9 10 $keys = []; 11 $lines = []; 12 foreach ($rows as $i => $row) { 13 if ($i === 0) { 14 $keys = $row; 15 continue; 16 } 17 $lines[] = array_combine($keys, $row); 18 } 19 foreach (array_chunk($lines, 100) as $i => $rows) { 20 Model::create($rows); 21 }

こんな感じで。
前提条件として、どのくらいの大きさのCSVなのか(何行何列?)も不明だし、PHPに割り当てたメモリの大きさも不明、テーブルの定義も不明なんでなんとも言えないですが。

投稿2020/06/01 01:18

phper.k

総合スコア3923

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hk206

2020/06/01 10:24

ありがとうございます。 CSVはトータル約100万行20列くらいですね。 仮装環境でのメモリは512MBです。
phper.k

2020/06/01 11:56

聞きたいのは仮想環境に割り当てたメモリではなく、PHPに割り当てたメモリです。 あと、テーブルの定義についても聞いています。
hk206

2020/06/02 01:24 編集

メモリに関しては現在は制限を設けずに実行しています。 memory_limit = -1 テーブルの定義については特殊なことはしておらず、例えば id(int) name(str) created_at updated_at deleted_at のみのテーブルでも現象は起きている状態です。 いろいろ試してみましたがCSVの処理に関わらず、insertを実行するとメモリが蓄積されます。
guest

0

transactionは使っていますか?
もし使っている場合、
Laravelではなく、PDOのレイヤで、commitするまで各種データを保存するので、リークというかメモリの使用量は増えます。
メモリ上限に達するくらい処理を繰り返しているということは、行数は相当量あると思うのですが、Bulk Insertの方が色々な箇所に優しい処理かと思います。

https://readouble.com/laravel/6.x/ja/queries.html#inserts

投稿2020/05/31 09:14

darum

総合スコア70

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hk206

2020/05/31 13:34

transaction使用せずに実行しています。 バルクインサート実行時もメモリの件はあまり変わりませんでした...。 ただ、おっしゃる通りメモリ云々に関わらずバルクインサートは使用した方が良いと思いますので、 修正しようと思います!ありがとうございます!
hentaiman

2020/05/31 19:51

英語記事だが自分の回答に書いた内容と全く同じことが書いてあったんで関係無いかと。
guest

0

ベストアンサー

一回回るごとにメモリ増大って、一回ごとにCSVの容量増えてるって意味ですか?
とりあえずマニュアル通りwhileで1行ずつ読み込みしてはどうですか?

投稿2020/05/21 13:46

hentaiman

総合スコア6426

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hk206

2020/05/21 15:16

回答ありがとうございます! 試してみましたが、結果変わらずでした...。 メモリが増えているのはCSVの読み込みは関係なく(1行づつ読み込めているので)、インサートの部分だと思っています。インサートはインサートでも質問に記載した"状況"の通りPDOのクエリ実行ではメモリはリークしません。 DB::insert()実行時に何らかのイベントが発火して例えばログなどを溜め込んでるのでは?と思っています。 説明不足ですみません...。
hentaiman

2020/05/21 15:40

本当ですね クエリビルダーがおかしいって感じの情報ありましたね なので諦めてstatementを使ってると・・・
swift_benkyo

2021/10/03 08:18

横から失礼します。同様の現象が起きましたが、下記issueのコメントが参考になりました。 https://github.com/laravel/framework/issues/27539#issuecomment-646112782 > DB::insert()実行時に何らかのイベントが発火して例えばログなどを溜め込んでるのでは? ご推察の通りのようです。 上記issueではそれをオフにするコードが記載されていました。 1年前の記事なので解決済みかとは思いますが一応。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問