2013-12-12 47 views
3

我在一個簡單的java控制檯應用程序中使用PreparedStatement來加載大量數據從InputStream優化插入海量數據

這是代碼:

public void readStopTimes(CSVReader reader) throws IOException, SQLException { 
     String insertSql = "INSERT INTO stop_times VALUES (null, ?, ?, ?, ?, ?)"; 
     PreparedStatement statement = db.prepareStatement(insertSql); 
     String [] nextLine; 
     long i = 0; 
     Chronometer chronometer = new Chronometer(); 
     while ((nextLine = reader.readNext()) != null) { 
      if(i++ != 0) { 
       statement.setString(1, nextLine[0]); 
       if(nextLine[1].isEmpty()) 
        statement.setNull(2, Types.TIME); 
       else 
        statement.setTime(2, Time.valueOf(nextLine[1])); 
       if(nextLine[2].isEmpty()) 
        statement.setNull(3, Types.TIME); 
       else 
        statement.setTime(3, Time.valueOf(nextLine[2])); 
       statement.setString(4, nextLine[3]); 
       statement.setInt(5, Integer.parseInt(nextLine[4])); 
       statement.addBatch(); 
      } 
      if(i++ % 1000 == 0) { 
       statement.executeBatch(); 
      } 
      if(chronometer.count() > 5000) { 
       chronometer.restart(); 
       log.debug("Analyzed {} rows", i); 
      } 
     } 
     statement.executeBatch(); 
     db.commit(); 
    } 

每1000個插入我正在執行的批處理,每5秒我打印的日誌。

從日誌中可以看出,該算法在開始時運行速度非常快,在前25秒內總共計數超過400萬行,然後減慢,在5秒內只有2行得到添加到批處理中。

我需要插入500多萬行,你有更快的選擇嗎?在MySQL

  • innodb_flush_log_at_trx_commit = 2或者,如果你能確保你的MySQL不會崩潰不是讓

  • +0

    我不知道答案,但對於測試:你可以在'statement.executeBatch();'之後添加'statement = db.prepareStatement(insertSql);''' –

    回答

    1
    • 禁用查詢緩存,它innodb_flush_log_at_trx_commit = 0
    • 如果啓用複製不是做sync_binlog = 0
    • 禁用斌日誌同步

    您可以嘗試通過Load data infile . . . . .命令將CSV文件直接放入MySql,該命令速度非常快。

    +0

    唯一有效的解決方案是加載數據infile,最終使用java預解析文件。 –

    0

    嘗試緊接在statement.executeBatch()之後進行緊接。而不僅僅是最後。這應該允許插入在你繼續進行時被刷新,因爲mysql會在你的插入上保留標籤,所以如果需要的話它可以將它們全部回滾。

    +0

    不幸的是沒有工作 –

    0

    嘗試添加多個批次而不是單個批次的數據。在每批次之後提交併跟蹤處理的數據。或者,您可以使用臨時表將數據添加到表中,一旦完成,重命名錶,以防止失敗,重新啓動或從保存點開始。