簡體   English   中英

解析巨大的 CSV 文件

[英]Parse huge CSV file

我有一個巨大的 CSV 文件

  1. 需要閱讀
  2. 證實
  3. 寫入數據庫

經過研究,我找到了這個解決方案

//configure input format using
CsvParserSettings settings = new CsvParserSettings();

//get an interator
CsvParser parser = new CsvParser(settings);
Iterator<String[]> it = parser.iterate(new File("/path/to/your.csv"), "UTF-8").iterator();

//connect to the database and create an insert statement
Connection connection = getYourDatabaseConnectionSomehow();
final int COLUMN_COUNT = 2;
PreparedStatement statement = connection.prepareStatement("INSERT INTO some_table(column1, column2) VALUES (?,?)"); 

//run batch inserts of 1000 rows per batch
int batchSize = 0;
while (it.hasNext()) {
    //get next row from parser and set values in your statement
    String[] row = it.next(); 
    //validation


    if (!row[0].matches(some regex)){
        badDataList.add(row);
        conitunue;
    }
    for(int i = 0; i < COLUMN_COUNT; i++){ 
        if(i < row.length){
            statement.setObject(i + 1, row[i]);
        } else { //row in input is shorter than COLUMN_COUNT
            statement.setObject(i + 1, null);   
        }
    }

    //add the values to the batch
    statement.addBatch();
    batchSize++;

    //once 1000 rows made into the batch, execute it
    if (batchSize == 1000) {
        statement.executeBatch();
        batchSize = 0;
    }
}
// the last batch probably won't have 1000 rows.
if (batchSize > 0) {
    statement.executeBatch();
}
// or use jook#loadArrays
 

context.loadInto("book")
      .batchAfter(500)
        .loadArrays(new ArrayList <String[]>)

但是,它仍然太慢,因為它在同一個線程中執行。 有沒有辦法通過多線程更快地做到這一點?

不要逐個迭代記錄,而是使用諸如LOAD DATA INFILE之類的命令批量導入數據:

JDBC:使用流從遠程 MySQL 數據庫導出/導入 CSV 原始數據(SELECT INTO OUTFILE / LOAD DATA INFILE)

注意:正如@XtremeBaumer 所說,每個數據庫供應商都有自己的用於從文件批量導入的命令。

可以使用不同的策略進行驗證,例如,如果可以使用 SQL 進行驗證,則可以將數據導入臨時表,然后選擇有效數據到目標表。

或者,您可以使用 Java 代碼驗證數據,然后對已驗證的數據使用批量導入,而不是一一導入。

首先你應該關閉語句和連接,使用 try-with.-resources.. 然后檢查(自動)提交事務性。

connection.setAutoCommit(true);

如果數據庫正在使用中,則在同一類別中將是表上的數據庫鎖。

正則表達式很慢,而是:

if (!row[0].matches(some regex)) {

private static Pattern SKIP_PATTERN = Pattern.compile(some regex);
...
if (SKIP_PATTERN.matcher(row[0]).matches()) { continue; }

如果有一個像整數 ID 這樣的運行數字,通過將數字保持在一個long的( statement.setLong(...) )中,批處理可能會更好。 如果該值是一個短的有限域,而不是 1000 個不同的 String 實例,則可以使用 string 到同一字符串的標識映射。 不確定這兩項措施是否有幫助。

多線程似乎很可疑,應該是最后的資源。 您可以寫入解析 CSV 的隊列,同時將其消耗到數據庫中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM