2013-12-12 48 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

    尝试添加多个批次而不是单个批次的数据。在每批次之后提交并跟踪处理的数据。或者,您可以使用临时表将数据添加到表中,一旦完成,重命名表,以防止失败,重新启动或从保存点开始。