JDBC批量插入性能

我需要将几百万条logging插入到MySQL数据库中。 我一次批量插入100万。 请参阅下面的代码。 这似乎很慢。 有没有什么办法来优化它?

try { // Disable auto-commit connection.setAutoCommit(false); // Create a prepared statement String sql = "INSERT INTO mytable (xxx), VALUES(?)"; PreparedStatement pstmt = connection.prepareStatement(sql); Object[] vals=set.toArray(); for (int i=0; i<vals.length; i++) { pstmt.setString(1, vals[i].toString()); pstmt.addBatch(); } // Execute the batch int [] updateCounts = pstmt.executeBatch(); System.out.append("inserted "+updateCounts.length); 

我有一个与MySQL类似的性能问题,并通过在连接url中设置useServerPrepStmtsrewriteBatchedStatements属性来解决它。

 Connection c = DriverManager.getConnection("jdbc:mysql://host:3306/db?useServerPrepStmts=false&rewriteBatchedStatements=true", "username", "password"); 

我想扩展Bertil的答案,因为我一直在试验连接URL参数。

rewriteBatchedStatements=true是重要的参数。 useServerPrepStmts默认已经是false,甚至将其更改为true在批量插入性能方面没有太大的区别。

现在我认为是时候写rewriteBatchedStatements=true如何显着提高性能。 这是通过rewriting of prepared statements for INSERT into multi-value inserts when executeBatch() ( Source ) rewriting of prepared statements for INSERT into multi-value inserts when executeBatch() 。 这意味着每次调用executeBatch()时,不要将以下n INSERT语句发送到mysql服务器:

 INSERT INTO X VALUES (A1,B1,C1) INSERT INTO X VALUES (A2,B2,C2) ... INSERT INTO X VALUES (An,Bn,Cn) 

它会发送一个INSERT语句:

 INSERT INTO X VALUES (A1,B1,C1),(A2,B2,C2),...,(An,Bn,Cn) 

你可以通过切换mysql日志logging(通过SET global general_log = 1 )观察它,这将login到每个语句发送到MySQL服务器的文件。

你可以用一个插入语句来插入多行,每次做几千个就可以大大加快速度,也就是说,而不是像INSERT INTO tbl_name (a,b,c) VALUES(1,2,3);插入3个INSERT INTO tbl_name (a,b,c) VALUES(1,2,3); INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(1,2,3),(1,2,3); (可能是JDBC .addBatch()现在可以做类似的优化 – 尽pipemysql addBatch过去一直未得到优化,只是发出个别查询 – 我不知道最近的驱动程序是否仍然如此)

如果你真的需要速度,使用LOAD DATA INFILE从逗号分隔的文件加载你的数据,我们可以做7-8倍的加速比做数千万的插入。

如果:

  1. 这是一个新表,或者要插入的数量大于已经插入的数据
  2. 桌子上有索引
  3. 在插入过程中,您不需要对表格进行其他访问

然后ALTER TABLE tbl_name DISABLE KEYS可以大大提高插入的速度。 完成后,运行ALTER TABLE tbl_name ENABLE KEYS开始构build索引,这可能需要一段时间,但不会像每次插入那样长。

您可以尝试使用DDBulkLoad对象。

 // Get a DDBulkLoad object DDBulkLoad bulkLoad = DDBulkLoadFactory.getInstance(connection); bulkLoad.setTableName(“mytable”); bulkLoad.load(“data.csv”); 
 try { // Disable auto-commit connection.setAutoCommit(false); int maxInsertBatch = 10000; // Create a prepared statement String sql = "INSERT INTO mytable (xxx), VALUES(?)"; PreparedStatement pstmt = connection.prepareStatement(sql); Object[] vals=set.toArray(); int count = 1; for (int i=0; i<vals.length; i++) { pstmt.setString(1, vals[i].toString()); pstmt.addBatch(); if(count%maxInsertBatch == 0){ pstmt.executeBatch(); } count++; } // Execute the batch pstmt.executeBatch(); System.out.append("inserted "+count);