トップ回答者
CSVファイルのACCESSへのインポート

質問
-
お世話になっております
現在 VS2005で C#と、ACCESS2000で開発を行っております。
TextFieldParserで、CSVを読み取り、TableAdapterのInsertQueryを使って、
データをテーブルに格納しています。
データ件数(約14万件)が多いため、時間がかかりすぎ、使い物になっていません。
以下ソースです
DataSetTableAdapters.TableAdapter da =
new DataSetTableAdapters.TableAdapter();//CSVファイルを処理する
TextFieldParser parser = new TextFieldParser(txtFileName.Text ,
System.Text.Encoding.GetEncoding("Shift_JIS"));
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(","); // 区切り文字はコンマ
parser.TrimWhiteSpace = true;
string[] row;while (!parser.EndOfData)
{
row = parser.ReadFields(); // 1行読み込み
// 配列rowの要素は読み込んだ行の各フィールドの値
try
{
//次の時にデータを取込む
//識別区分:0かつ更新区分:0or1
if ((string)row[1] == "0" && ((string)row[2] == "0" || (string)row[2] == "1"))
{
da.InsertQuery(row[0], row[3], row[4], row[5], row, row[11], row[12], row[14], row[15],
row[16], row[17], row[18], row[19], row[20], row[21], row[22],
row[4] + row[5] + row, row[5] + row
);
}
}
catch (Exception e)
{
throw e;
}
}da.Dispose();
parser.Dispose();ここまで。
SQLServerなら、DTSを使ったり、
ACCESSVBAなら、インポート定義を使ってCSVファイルをインポートする方法がありますが、
C#を使ってうまくやる方法は無いのでしょうか?
ご教授ください。
回答
-
外池です。VBですが、ちょこっと試してみました。横に23個のフィールドがあって、14万行のデータを持つCSVファイルを作ってみて、読み取りのスピードを測ってみたところ・・・
このファイルを
1)TextParserで、","をデリミタに指定して読み取る場合(お示し頂いたプログラムに相当)
と
2)StreamReaderで単純に一行ずつ読み出して、さらに、String型のSplitメソッドで分割した場合
と
比較すると、1)が最低でも20倍程度時間がかかりました。もしかすると、30倍、40倍違うかもしれません。なお、分割したrow[]を繋ぎ合わせる操作はしていません。とにかく読み出す部分だけでもこれぐらいの差があるということで。
参考になれば幸いです。
-
外池 さんからの引用 外池と申します。私が自身でやってみれば分かることではあるのですが・・・、
14万件・・・、遅い・・・、使い物になっていない・・・、
その本当の理由がどこにあるのか、気になるところです。
TextParserなのか、それとも、
TableAdapterのInsertQueryなのか?
あるいは、はたまた、
その途中にある文字列型配列の操作か(14万回の新たな配列の生成、あと、配列要素同士の連結)。
なんとなく、TextParserと、後続の文字列型配列の操作に問題があるような気もします・・・。(あくまで、直感的な印象)
外池様
本当の理由・・・
私なりに調べてみたのですが、
TextParserだけだと、14万件読み取るのに、5分強(これでも遅いですが・・・・)
InsertQueryを入れると、2時間以上かかってしまいます。
思うに、INSERT文を14万回も走らせているから時間がかかるのかなと?
なにぶんVS2005+C#の開発に不慣れなもので、
デザイナで作られたInsertQueryのカスタマイズ方法が良くわかっていません。
この辺がうまく出来れば、InsertQueryの発行回数が減らすことができて、
スピードアップが出来ると思ってはいるのですが・・・・
-
こんにちは。森田 知良です。
初音玲さん、外池さん、有用な情報ありがとうございました。
TAKAUZIさん、フォーラムのご利用ありがとうございます。
私の方で初音玲さん、外池さんの情報は、有用な情報と判断しましたので、
勝手ながら回答済みチェックを付けさせていただきました。
TAKAUZIさんは、回答済みチェックを解除することもできますのでご確認ください。
回答済みチェックが付くことにより、有用な情報を探している方が情報を見つけやすくなります。
有効な回答があった場合は、なるべく回答済みボタンを押してチェックを付けてくださるようお願いします。また、追加の質問等ありましたら、是非もう一度投稿してくださるようお願いします。
それでは、これからもフォーラムのご利用をよろしくお願いいたします。
すべての返信
-
外池です。VBですが、ちょこっと試してみました。横に23個のフィールドがあって、14万行のデータを持つCSVファイルを作ってみて、読み取りのスピードを測ってみたところ・・・
このファイルを
1)TextParserで、","をデリミタに指定して読み取る場合(お示し頂いたプログラムに相当)
と
2)StreamReaderで単純に一行ずつ読み出して、さらに、String型のSplitメソッドで分割した場合
と
比較すると、1)が最低でも20倍程度時間がかかりました。もしかすると、30倍、40倍違うかもしれません。なお、分割したrow[]を繋ぎ合わせる操作はしていません。とにかく読み出す部分だけでもこれぐらいの差があるということで。
参考になれば幸いです。
-
外池 さんからの引用 外池と申します。私が自身でやってみれば分かることではあるのですが・・・、
14万件・・・、遅い・・・、使い物になっていない・・・、
その本当の理由がどこにあるのか、気になるところです。
TextParserなのか、それとも、
TableAdapterのInsertQueryなのか?
あるいは、はたまた、
その途中にある文字列型配列の操作か(14万回の新たな配列の生成、あと、配列要素同士の連結)。
なんとなく、TextParserと、後続の文字列型配列の操作に問題があるような気もします・・・。(あくまで、直感的な印象)
外池様
本当の理由・・・
私なりに調べてみたのですが、
TextParserだけだと、14万件読み取るのに、5分強(これでも遅いですが・・・・)
InsertQueryを入れると、2時間以上かかってしまいます。
思うに、INSERT文を14万回も走らせているから時間がかかるのかなと?
なにぶんVS2005+C#の開発に不慣れなもので、
デザイナで作られたInsertQueryのカスタマイズ方法が良くわかっていません。
この辺がうまく出来れば、InsertQueryの発行回数が減らすことができて、
スピードアップが出来ると思ってはいるのですが・・・・
-
外池 さんからの引用 外池です。VBですが、ちょこっと試してみました。横に23個のフィールドがあって、14万行のデータを持つCSVファイルを作ってみて、読み取りのスピードを測ってみたところ・・・
このファイルを
1)TextParserで、","をデリミタに指定して読み取る場合(お示し頂いたプログラムに相当)
と
2)StreamReaderで単純に一行ずつ読み出して、さらに、String型のSplitメソッドで分割した場合
と
比較すると、1)が最低でも20倍程度時間がかかりました。もしかすると、30倍、40倍違うかもしれません。なお、分割したrow[]を繋ぎ合わせる操作はしていません。とにかく読み出す部分だけでもこれぐらいの差があるということで。
参考になれば幸いです。
外池様
なるほど、
TextParserより、StreamReaderの方が早く処理が出来るのですね?
試してみたいと思います
有難うございました。
-
初音玲 さんからの引用 TAKAUZI さんからの引用 開発マシンではACCESSはインストールしていますが、
提供先のマシンではACCESSはインストールしていません。
そうだとすると、提供先で動かなくなってしまうのでTransferTextメソッドを使う方法はだめですねー。
# Access使って開発してるっていうのは、Access2002形式のmdbファイルを使ってって意味なのですね。
そうなると、外池さんが示されているアプローチが正解かもですね。
提供先ではACCESSがインストールしていないと、TransferTextメソッドが使えないのですね?
データベースを使うのにMDB形式のファイルを使っているだけです。
あまり、提供先の環境を変えたくないので、データベースをMDBで利用していますが、
他にいい方法があれば、そちらに変更することも考えています。
とりあえず、読み取り時間だけでも早くしたいので、外池様が提示していただいた
方法を試してみます。
-
こんにちは。森田 知良です。
初音玲さん、外池さん、有用な情報ありがとうございました。
TAKAUZIさん、フォーラムのご利用ありがとうございます。
私の方で初音玲さん、外池さんの情報は、有用な情報と判断しましたので、
勝手ながら回答済みチェックを付けさせていただきました。
TAKAUZIさんは、回答済みチェックを解除することもできますのでご確認ください。
回答済みチェックが付くことにより、有用な情報を探している方が情報を見つけやすくなります。
有効な回答があった場合は、なるべく回答済みボタンを押してチェックを付けてくださるようお願いします。また、追加の質問等ありましたら、是非もう一度投稿してくださるようお願いします。
それでは、これからもフォーラムのご利用をよろしくお願いいたします。
-
森田様、回答済みのチェックが遅くなり、申し訳ありません。(イロイロと大変だったもので・・・・
)
今回の解決策をUPします。
//*******ここから*********//
//使用DB宣言
string connStr;
string SqlCommand, InsertIntoCMD = "";
DataSet DSCommand = new DataSet(); ;
//構成ファイルからDB接続コマンド取得し、接続
connStr = ConfigurationManager.ConnectionStrings["接続情報"].ConnectionString;
//接続
OleDbConnection cnn = new OleDbConnection(connStr);
cnn.Open();
//指定ファイルの読み込み
System.IO.StreamReader parser = new System.IO.StreamReader(txtFileName.Text,
System.Text.Encoding.GetEncoding("Shift_Jis"));
string Read_Data;
string[] row;while ((Read_Data = parser.ReadLine()) != null)
{
//読み込んだファイルを『,』で区切る
row = Read_Data.Split(',');// 配列rowの要素は読み込んだ行の各フィールドの値
try
{
//次の時にデータを取込む
InsertIntoCMD = "SELECT ' + ”分割したCSVファイルの項目”
db.CommandText = "INSERT INTO 取込み先テーブル " +
"( 取込み先の項目 ) " + InsertIntoCMD;
db.ExecuteNonQuery();
}catch (Exception e)
{
throw e;
}
}cnn.Close();
db.Dispose();
parser.Close();//*******ここまで*********//
です。
少しソースは編集しているので、このままでは動かないですが、
データセットデザイナ(?)で作った、インサートクエリーを実行させるより、
直接データベースにつないで、INSERT文を実行したほうが、早く実行が出来るみたいです。
この解決方法で、5分強で14万件のデータの取込が完了しました。
ACCESSのSQLで、複数行のデータを1回でINSERT出来る方法があれば、INSERTの回数を減らすことが出来るので、
もう少し早くなるのでは?と思います。
なにぶんC#の製造(というより、VSでの製造)に不慣れなもので、DBや、帳票系の処理がまったくチンプンカンプンでした・・・
皆様は、DBの設計などにデザイナって使っているのでしょうか?
ご協力有難うございました。