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

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

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

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

CentOS

CentOSは、主にRed Hat Enterprise Linux(RHEL)をベースにした、フリーのソフトウェアオペレーティングシステムです。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

PHP

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

シェル

シェル(shell)はUnix や Linux 系のOSで使用されるコマンドインタプリタを指します。

Q&A

解決済

4回答

2848閲覧

シェルスクリプトによるCSVデータ(件数不確定)のDB挿入とphpでechoした値の受け取りについて

jun_1989

総合スコア17

bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

CentOS

CentOSは、主にRed Hat Enterprise Linux(RHEL)をベースにした、フリーのソフトウェアオペレーティングシステムです。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

PHP

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

シェル

シェル(shell)はUnix や Linux 系のOSで使用されるコマンドインタプリタを指します。

0グッド

0クリップ

投稿2017/07/31 05:10

お世話になります。

数万件〜数百万件になるCSVファイルのDBへのinsert及びupdateに関して質問させてください。

現在、AWSのS3に定期的にアップされるCSVファイルをダウンロードしてローカルに保存し、そのCSVのデータをDBに挿入・更新するphpのプログラム(get-csv.php)を書いています。

CSVファイルのデータ件数が数万件〜数百万件(毎回件数は違います)あるので、一回で処理しようとするとメモリが飛んでしまいます。

ですのでget-csv.phpでは、メモリ節約のため一回の処理数を1万件までにして、シェルスクリプトを実行する際に

bash

1for i in `seq 1 100` 2do 3 php get-csv.php $i 4done

という具合に、get-csv.phpに引数を渡して引数が1の時は1件目〜1万件目、2の時は1万件目〜2万件目、3の時は2万件目〜3万件目・・・という処理をphp側で書いています。

本当はforではなくwhileなどを使ってループを制御したいのですが、無知のためやり方がわかりません。

whileで回したget-csv.phpがechoする値(NULLか否か)を使ってwhileの条件判定をするのだろうとは思いますが、phpで吐いた値をシェルスクリプトで受け取る方法が恥ずかしながらわかりません。

質問と致しましては

①phpのプログラムでechoした値をシェルスクリプトで受け取る方法(シェルスクリプトのwhileの条件式で使うためです)

②そもそも件数の多いCSVファイルの処理として、私が行っている方法は適切かどうか。他に考えられる処理の仕方があるのかどうか。

の2点です。

どちらか1点でも構いませんので、わかる方がいらっしゃいましたらご教授のほどよろしくお願い申し上げます。

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

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

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

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

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

guest

回答4

0

LOAD DATA INFILEを使用するのはどうでしょう?
insertやupdateで行うよりも高速だと思います。
データ量により一括で処理できない場合は、CSVファイルを分割する必要はありますが。

MySQL 5.6 リファレンスマニュアル 13.2.6 LOAD DATA INFILE 構文

投稿2017/08/01 01:14

sazi

総合スコア25138

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

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

jun_1989

2017/08/04 11:34

ご回答ありがとうございます!「LOAD DATA INFILE」初めて聞きました!勉強になります。
guest

0

①phpのプログラムでechoした値をシェルスクリプトで受け取る方法(シェルスクリプトのwhileの条件式で使うためです)

phpからの戻り値を得る方法として2つの方法を考えました。どちらも終了条件に使えます

php

1 2 RC=$(php -r "echo 'AAA';") 3 echo $RC 4 5 php -r "exit(2);" 6 rc=$? 7 echo $rc

②そもそも件数の多いCSVファイルの処理として、私が行っている方法は適切かどうか。他に考えられる処理の仕方があるのかどうか。

大して違わないですが入力ファイルを分割する方法(5個並列)

bash

1 split -l 10000 data.csv out_ 2 jj=1 3 for ff in out_* 4 do 5 php -r "echo '$ff';" & #入力ファイルをパラメータでまたはSTDINで 6 if [ $(( jj % 5 )) -eq 0 ]; then 7 wait 8 fi 9 ((jj++)) 10 done 11 rm out_*

並列実行はinsert時にdeadlockが発生しないテーブルの場合ですが・・・

投稿2017/07/31 23:13

編集2017/08/01 01:34
A.Ichi

総合スコア4070

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

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

jun_1989

2017/08/04 11:37

ご回答ありがとうございます!phpもbashも勉強中なので参考になります!
guest

0

bash

1seq 1 $(wc -l source.csv|awk '{print int($1/10000)}')|xargs -n1 php get-csv.php

でどうでしょうか?csvの件数(行数)を気にしなくてよく、phpの戻り値も不要になります。
上記1行でfor〜doneの4行分に相当します。

  • 件数不確定とのことなので、wc -l source.csvで件数(行数)を調べます

  • 1万件づつの処理にするために分割数を算出します awk '{print int($1/10000)}'

  • 連番を作成しますseq 1 $(wc -l source.csv|awk '{print int($1/10000)}')

  • get-cdv.phpの引数に値を渡します。|xargs -n1 php get-csv.php

試しに、以下のコマンドを実行していけば、どんなことをしているかわかるはずです。(phpの代わりにechoを使ってテストしてます)
0. wc -l source.csv
0. wc -l source.csv|awk '{print int($1/10000)}'
0. seq 1 $(wc -l source.csv|awk '{print int($1/10000)}')|xargs echo get-csv.php
0. seq 1 $(wc -l source.csv|awk '{print int($1/10000)}')|xargs -n1 echo get-csv.php

個々のコマンドは調べてください

投稿2017/07/31 05:57

編集2017/07/31 12:09
NCC1701

総合スコア1680

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

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

jun_1989

2017/07/31 06:36

ご回答ありがとございます。初めて目にした文で勉強になります。可能でしたらご教授いただきたいのですが、そちらの文はforの中で使用するという認識でよろしいでしょうか。またprint int($1/10000)の部分はMAXで1万回forを回すという認識でよろしいでしょうか。恐縮ですが、よろしくお願いします。
NCC1701

2017/07/31 07:22

1行ですべてです。forは使いません
jun_1989

2017/07/31 08:12

ご丁寧に解説頂き本当に感謝申し上げます。1~4の命令を実行して、何をしているかがわかりました!forの回数を求めていたんですね。勉強になります。早速使用させていただきます。
guest

0

ベストアンサー

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文ができあがります。

投稿2017/07/31 05:40

yambejp

総合スコア114583

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

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

jun_1989

2017/07/31 06:19

ご回答ありがとうございます。説明不足で申し訳ございません。SQLはmysqlを使用しております。現状、foreachにてCSVのデータを一件ずつinsertしております。教えていただいた方法だと、シェルでforを回すのではなく、一回でCSVのデータを全部取得して、phpで分割して挿入するという認識でよろしいでしょうか。お手数ですが、可能でしたらご回答よろしくお願いします。
yambejp

2017/07/31 06:24

ごめんなさい、ちょっとこちらの認識がちがうのかもしれません。 今回の目的はCSVデータを一括で読めないのをなんとかしたい また、高速に処理したいということではないのでしょうか? CSVデータは1行読み出してはINSERT形式に変換してテンポラリに 書き出していくというイメージです。 最終的にINSERT文が大量にできあがりますが、INSERT文を 乱発するよりバルク形式のINSERTの方が数十~数百倍は速いと 思います。 逆にCSVで出力するのではなくdumpデータとして吐き出してもらえれば もっと効率的でしょう
jun_1989

2017/07/31 06:48

いえ、ご認識の通りです。大量のCSVデータを高速に処理したいというのが望みです。現状、phpでCSVデータを一件ずつinsertしていたので、教えていただいたバルク形式の挿入を試してみたいと思います。 >逆にCSVで出力するのではなくdumpデータとして吐き出してもらえればもっと効率的でしょう そうなんですね!勉強になります。ただ今回の案件ではCSV出力を指定されていますので、また別の機会に試してみたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問