2016-04-19 9 views
3

入力セット:50000を超えるエントリを含む数千(> 10000)のcsvファイル。 出力:これらのデータをmysql dbに格納します。単一トランザクションでmysqlに50000+レコードを格納するベストプラクティス

アプローチ: 各ファイルを読み込んでデータベースに格納します。以下は同じもののコードスニペットです。この方法がOKかどうかをお勧めします。

PreparedStatement pstmt2 = null; 
try 
{ 
pstmt1 = con.prepareStatement(sqlQuery); 
result = pstmt1.executeUpdate(); 
con.setAutoCommit(false); 
sqlQuery = "insert into " 
     + tableName 
     + " (x,y,z,a,b,c) values(?,?,?,?,?,?)"; 
pstmt2 = con.prepareStatement(sqlQuery); 
Path file = Paths.get(filename); 

lines = Files.lines(file, StandardCharsets.UTF_8); 
final int batchsz = 5000; 
for (String line : (Iterable<String>) lines::iterator) { 

    pstmt2.setString(1, "somevalue"); 
    pstmt2.setString(2, "somevalue"); 
    pstmt2.setString(3, "somevalue"); 
    pstmt2.setString(4, "somevalue"); 
    pstmt2.setString(5, "somevalue"); 
    pstmt2.setString(6, "somevalue"); 
    pstmt2.addBatch(); 
    if (++linecnt % batchsz == 0) { 
     pstmt2.executeBatch(); 
    } 
} 
int batchResult[] = pstmt2.executeBatch(); 
pstmt2.close(); 
con.commit(); 

} catch (BatchUpdateException e) { 
    log.error(Utility.dumpExceptionMessage(e)); 

} catch (IOException ioe) { 
    log.error(Utility.dumpExceptionMessage(ioe)); 
} catch (SQLException e) { 
    log.error(Utility.dumpExceptionMessage(e)); 
} finally { 
    lines.close(); 
    try { 
     pstmt1.close(); 
     pstmt2.close(); 
    } catch (SQLException e) { 
     Utility.dumpExceptionMessage(e); 
    } 
} 
+0

大量のエクスポートをダンプまたはインポートしてすべてを挿入しようとしました。 –

+3

用語を明確にしますか? SQLワールドダンプでは、一連のSQLクエリ、CSV、または所有者の形式のいずれかとして、データベースからエクスポートされたデータを意味します。ダンプまたはデータベースからデータを取得することは、インポートまたはロードと呼ばれます。あなたの質問を明確にすることができたら... – e4c5

+0

私は最近、同様の問題を処理しました。私の場合、データは600,000+です。私の解決策は、マルチスレッドとブロックキューを使用してデータをインポートすることです。ただし、マルチスレッドではパフォーマンスが実際に向上するわけではなく、応答時間が短縮されるだけです。本当に速くしたい場合は、並列ソリューションを検討してください。しかし、50,000は並列化するには小さすぎますが、複雑さは利益をはるかに上回ります。したがって、バルク挿入のシングルスレッドを貼っておくことをお勧めします。 –

答えて

1

@Ridrigoがすでに指摘したように、LOAD DATA INFILEは移動するための方法です。 Javaはまったく必要ではありません。

CSVの形式がデータベースに直接挿入できるものでない場合は、Javaコードによって画像がリネームされます。これを使用して、CSVを再編成/変換し、データベースに書き込む代わりに別のCSVファイルとして保存します。

また、CSVを含むフォルダを反復処理するためのJavaコードを使用することができ、その後、これは、個々のSQLクエリを実行しているよりもはるかに高速であることをあなたが見つける

Runtime r = Runtime.getRuntime(); 
Process p = r.exec("mysql -p password -u user database -e 'LOAD DATA INFILE ...."); 

ためのシステムコマンドを実行しますCSVファイルの各行に適用されます。

2

これまで、このような状況でLOAD DATA INFILEを使用しました。

LOAD DATA INFILE文は、テキストファイルの行を テーブルに非常に高速で読み込みます。 LOAD DATA INFILEは、 SELECT ... INTO OUTFILEの補数です。 (14.2.9.1項「SELECT ... INTO 構文」を参照してください。)表からファイルにデータを書き込むには、SELECT ... INTO OUTFILEを使用します。ファイルをテーブルに読み込むには、LOAD DATA INFILEを使用します。 FIELDSおよびLINES句の の構文は、 ステートメントの場合と同じです。両方の句はオプションですが、FIELDSは両方とも指定されている場合はLINES より前になければなりません。

IGNORE番号のLINESオプションを使用すると、ファイルの先頭にある行を無視できます。たとえば、列名を含む最初のヘッダ行をスキップするように1行を無視使用することができます表テストへのデータINFILE「/tmp/test.txt」

LOADは、1行を無視します。

http://dev.mysql.com/doc/refman/5.7/en/load-data.html

+0

これらのcsvファイル形式はカスタムです。いくつかのデバイスの詳細を含むいくつかの行があり、その後、列名とそれぞれの値が続きます。それらの最初の行を無視することはできますか? – basu

+0

「無視」で編集してください。 – Rodrigo

+0

詳細な説明に本当に役立ちます。 – basu

関連する問題