我试图在RDS内部从一个MySQL实例移动大量记录。它们位于不同的VPC和不同的AWS账户上,因此我无法创建一个可以为我复制的数据管道。
我编写了一个连接导入数据库和导出数据库的快速java程序,并执行以下操作:
SELECT MAX(primary_key) FROM table
SELECT * FROM table WHERE(primary_key > max_from_import) LIMIT 1000000
INSERT INTO table (col1....coln) VALUES (?....n?)
使用这种方法,我能够看到每小时导入大约100000条记录,但我知道从this question开始,优化插入的方法不是每次都创建一个新的查询,而是每个插入附加更多数据。即。
INSERT INTO table (col1...coln) VALUES (val1...valn), (val1...valn)....(val1...valn);
jdbc驱动程序是否知道这样做,或者我是否可以进行某种优化以改善插入运行时间?
更新 这两个答案都建议使用添加和执行批处理,以及删除自动提交。删除自动提交略有改进(10%),批处理的运行时间小于单个插入的50%。
答案 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);
。
如果您使用的是“准备好的语句”,则可以使用null
和addBatch
个函数。内部循环使用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) ...