質問: お世話になります。 数万件〜数百万件になるCSVファイルのDBへのinsert及びupdateに関して質問させてください。 現在、AWSのS3に定期的にアップされるCSVファイルをダウンロードしてローカルに保存し、そのCSVのデータをDBに挿入・更新するphpのプログラム(get-csv.php)を書いています。 CSVファイルのデータ件数が数万件〜数百万件(毎回件数は違います)あるので、一回で処理しようとするとメモリが飛んでしまいます。 ですのでget-csv.phpでは、メモリ節約のため一回の処理数を1万件までにして、シェルスクリプトを実行する際に ``` for i in `seq 1 100` do php get-csv.php $i done ``` という具合に、get-csv.phpに引数を渡して引数が1の時は1件目〜1万件目、2の時は1万件目〜2万件目、3の時は2万件目〜3万件目・・・という処理をphp側で書いています。 本当はforではなくwhileなどを使ってループを制御したいのですが、無知のためやり方がわかりません。 whileで回したget-csv.phpがechoする値(NULLか否か)を使ってwhileの条件判定をするのだろうとは思いますが、phpで吐いた値をシェルスクリプトで受け取る方法が恥ずかしながらわかりません。 質問と致しましては 1phpのプログラムでechoした値をシェルスクリプトで受け取る方法(シェルスクリプトのwhileの条件式で使うためです) 2そもそも件数の多いCSVファイルの処理として、私が行っている方法は適切かどうか。他に考えられる処理の仕方があるのかどうか。 の2点です。 どちらか1点でも構いませんので、わかる方がいらっしゃいましたらご教授のほどよろしくお願い申し上げます。
回答: SQLの種別は何を予定されているのでしょうか? たとえばMySQLだとしたら基本的にはCSVをSQL文に変換した上で INSERT INTO ~ VALUES(x,x,x),(y,y,y),(Z,Z,Z)・・・・ というバルク形式のデータとして取り込むのが効率的です。 一度に取り込む量は1万件程度でまとめるとトラブル時の検証も やりやすいと思います。 具体的には INSERT INTO ~ ・・・・; INSERT INTO ~ ・・・・; INSERT INTO ~ ・・・・; INSERT INTO ~ ・・・・; のようなSQL文を何万行とテンポラリで保持しておき、 まずは1万行単位でsplitする その上で月末の;をとり、2行目以降のINSERT INTO・・・VALUES を除外すると1万件のバルクINSERT文ができあがります。