mysql jdbc驱动程序类是否知道批量执行多个插入?

时间:2017-06-14 16:56:51

标签: java mysql database optimization

我试图在RDS内部从一个MySQL实例移动大量记录。它们位于不同的VPC和不同的AWS账户上,因此我无法创建一个可以为我复制的数据管道。

我编写了一个连接导入数据库和导出数据库的快速java程序,并执行以下操作:

  1. 使用SELECT MAX(primary_key) FROM table
  2. 在table.primary_key中查询导入数据库中最高的数据库
  3. 使用SELECT * FROM table WHERE(primary_key > max_from_import) LIMIT 1000000
  4. 从导出表中获取结果集
  5. 从导入连接创建PreparedStatement对象,并将queryString设置为INSERT INTO table (col1....coln) VALUES (?....n?)
  6. 遍历结果集并将准备好的语句列设置为结果游标中的列(对数据进行一些小的操作),在PreparedStatement对象上调用execute,清除它的'参数,然后转到下一个结果。
  7. 使用这种方法,我能够看到每小时导入大约100000条记录,但我知道从this question开始,优化插入的方法不是每次都创建一个新的查询,而是每个插入附加更多数据。即。

    INSERT INTO table (col1...coln) VALUES (val1...valn), (val1...valn)....(val1...valn);
    

    jdbc驱动程序是否知道这样做,或者我是否可以进行某种优化以改善插入运行时间?

    更新 这两个答案都建议使用添加和执行批处理,以及删除自动提交。删除自动提交略有改进(10%),批处理的运行时间小于单个插入的50%。

2 个答案:

答案 0 :(得分:1)

首先创建与Destination数据库的JDBC连接,并将其自动提交属性设置为false

之后在循环中执行以下操作

从源数据库中读取N(例如1000)行数并将其写入目标数据库。

在一些插入后提交目标数据库连接。

下面给出了更多想法的示例代码

Connection sourceCon = getSourceDbConnction();
Connection destCon = getDestinationDbConnction();
destCon.setAutoCommit(false);
int i=0;
String query;
while((query=getInsertQuery()!=null)
{         
     statement.executeUpdate(query);
     i++;
     if(i%10 == 0)
     {
       destCon.commit();
       i=0;
     }
}
destCon.commit();

getInsertQuery函数应该以{{1​​}}格式提供字符串。 如果处理完所有表,它也应该返回INSERT INTO table (col1...coln) VALUES (val1...valn), (val1...valn)....(val1...valn);

如果您使用的是“准备好的语句”,则可以使用nulladdBatch个函数。内部循环使用executeBatch函数添加值。在一些插入后调用addBatch

答案 1 :(得分:1)

您需要使用批量插入。在内部,Connector / J(MySQL JDBC驱动程序)可以将批量插入重写为多值插入语句。

(请注意,这是默认的Connector / J行为。您可以添加 JDBC URL的选项useServerPrepStmts=true以启用服务器端预处理语句

代码如下所示:

 try(PreparedStatement stmt = connection.prepareStatement(sql)) {
    for(value : valueList) {   
      stmt.clearParameters();     
      stmt.setParameter(1, value);
      stmt.addBatch();
    }
    stmt.executeBatch();
 }

上面的代码将生成一个多值插入:

INSERT tablename(field) VALUES(value1), (value2), (value3) ...