2016-04-19 1 views
3

Eingabe-Set: Tausende (> 10000) von CSV-Dateien, die jeweils> 50000 Einträge enthalten. Ausgabe: Speichern Sie diese Daten in mysql db.Was ist Best Practice, um mehr als 500 Datensätze in mysql in einer einzigen Transaktion zu speichern

Ansatz genommen: Lesen Sie jede Datei und speichern Sie die Daten in der Datenbank. Unten ist das Code-Snippet für dasselbe. Bitte schlagen Sie vor, ob dieser Ansatz in Ordnung ist oder nicht.

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

Ich würde versuchen, einen Massenexport zu dumpen oder zu importieren, um sie alle einzufügen. –

+3

Sollen wir die Terminologie klären? In SQL World Dump bedeutet Daten, die aus einer Datenbank entweder als eine Reihe von SQL-Abfragen, CSV oder ein Besitzerformat exportiert wurde. Daten von einem Dump oder in eine Datenbank zu bekommen heißt Importieren oder Laden. Jetzt, wenn Sie Ihre Frage klären könnten ... – e4c5

+0

Ich habe kürzlich ein ähnliches Problem behandelt, in meinem Fall sind die Daten 600.000+. Meine Lösung verwendet Multithread und blockierende Warteschlange, um die Daten zu importieren. Multithreading verbessert jedoch nicht die Leistung, es reduziert nur die Antwortzeit. Wenn Sie es wirklich schneller machen wollen, sollten Sie eine parallele Lösung in Erwägung ziehen. Aber 50.000 sind zu klein, um parallelisiert zu werden, die Komplexität überwiegt den Nutzen bei weitem. Daher schlage ich vor, dass Sie mit Single-Thread mit Bulk-Insertion bleiben. –

Antwort

1

Wie @Ridrigo bereits ausgeführt hat, ist LOAD DATA INFILE der Weg zu gehen. Java wird überhaupt nicht benötigt.

Wenn das Format Ihrer CSV nicht direkt in die Datenbank eingefügt werden kann, kann Ihr Java-Code das Bild rendern. Verwenden Sie es, um die CSV zu reorganisieren/umzuwandeln und sie als eine andere CSV-Datei zu speichern, anstatt sie in die Datenbank zu schreiben.

Sie können auch den Java-Code verwenden, um durch die Ordner zu durchlaufen, die die CSV enthält, und dann für die

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

den Systembefehl ausführen werden Sie feststellen, dass dies viel viel schneller als einzelne SQL-Abfragen laufen für jede Zeile der CSV-Datei.

2

Ich habe LOAD DATA INFILE in Situationen wie dieser in der Vergangenheit verwendet.

Die Anweisung LOAD DATA INFILE liest Zeilen mit sehr hoher Geschwindigkeit aus einer Textdatei in eine Tabelle. LOAD DATA INFILE ist die Ergänzung von SELECT ... IN OUTFILE. (Siehe Abschnitt 14.2.9.1, "SELECT ... INTO Syntax".) Um Daten aus einer Tabelle in eine Datei zu schreiben, verwenden Sie SELECT ... INTO OUTFILE. Verwenden Sie LOAD DATA INFILE, um die Datei zurück in eine Tabelle zu lesen. Die -Syntax der FIELDS- und LINES-Klauseln ist für beide -Anweisungen identisch. Beide Klauseln sind optional, FIELDS müssen jedoch LINES vorausgehen, wenn beide angegeben sind.

Die Option IGNORE number LINES kann verwendet werden, um Zeilen am Anfang der Datei zu ignorieren. Zum Beispiel können Sie 1 LINES IGNORE, um eine Kopfzeile mit Spaltennamen überspringen:

LOAD DATA INFILE '/tmp/test.txt' INTO TABLE Test IGNORE 1 LINES;

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

+0

Dieses CSV-Dateiformat ist benutzerdefiniert.Es hat einige Zeilen mit einigen Gerätedetails initialisiert und danach werden die Spaltennamen und ihre jeweiligen Werte fortgesetzt. Können diese Anfangszeilen ignoriert werden? – basu

+0

Edit mit "IGNORE LINES", hoffe es hilft. – Rodrigo

+0

Wirklich hilfreich mit Ihrer detaillierten Beschreibung. – basu

Verwandte Themen