使用预准备语句批量更新在Java中批量插入

Mri*_*moy 30 java bulkinsert resultset prepared-statement

我试图用Java填充一个带有大约50,000行10列的结果集,然后使用batchExecute方法将它们插入到另一个表中PreparedStatement.

为了使这个过程更快,我做了一些研究,发现在将数据读入resultSet时,fetchSize起着重要的作用.

拥有一个非常低的fetchSize可能导致太多的服务器访问,并且非常高的fetchSize可以阻止网络资源,所以我尝试了一点,并设置了适合我的基础设施的最佳大小.

我正在读取此resultSet并创建插入语句以插入到另一个数据库的另一个表中.

像这样的东西(只是一个样本,而不是真正的代码):

for (i=0 ; i<=50000 ; i++) {
    statement.setString(1, "a@a.com");
    statement.setLong(2, 1);
    statement.addBatch();
}
statement.executeBatch();
Run Code Online (Sandbox Code Playgroud)
  • executeBatch方法是否会尝试一次发送所有数据?
  • 有没有办法定义批量大小?
  • 有没有更好的方法来加快批量插入的过程?

在批量更新(50,000行10列)时,使用可更新ResultSet或PreparedStaement批量执行是否更好?

seh*_*seh 46

我将依次解决您的问题.

  • executeBatch方法是否会尝试一次发送所有数据?

这可能因每个JDBC驱动程序而异,但我研究的少数几个将迭代每个批处理条目,并将每个参数与准备好的语句句柄一起发送到数据库以便执行.也就是说,在上面的示例中,将使用50,000对参数执行50,000个预处理语句,但这些50,000个步骤可以在较低级别的"内循环"中完成,这是节省时间的地方.相当拉伸的类比,就像从"用户模式"退出到"内核模式"并在那里运行整个执行循环.您可以为每个批次条目节省潜入和退出该较低级别模式的成本.

  • 有没有办法定义批量大小

您通过在执行批处理之前推送50,000个参数集来隐式定义它Statement#executeBatch().批量大小为1也同样有效.

  • 有没有更好的方法来加快批量插入的过程?

考虑在批量插入之前显式打开事务,然后提交它.不要让数据库或JDBC驱动程序在批处理中的每个插入步骤周围强加事务边界.您可以使用该Connection#setAutoCommit(boolean)方法控制JDBC层.首先将连接从自动提交模式中取出,然后填充批次,启动事务,执行批处理,然后通过提交事务Connection#commit().

这个建议假定您插入不会并发作家百家争鸣,并假定这些事务边界会给你在插入使用源表中读取充分一致的值.如果不是这样的话,那就赞成正确而不是速度.

  • 使用可更新ResultSetPreparedStatement批量执行是否更好?

没有什么比使用您选择的JDBC驱动程序更好的测试,但我希望后者PreparedStatement- Statement#executeBatch()并将在这里胜出.语句句柄可以具有关联的列表或"批处理参数"数组,每个条目是在调用Statement#executeBatch()Statement#addBatch()(或Statement#clearBatch())之间提供的参数集.每次调用时列表都会增长,addBatch()直到你打电话才会刷新executeBatch().因此,Statement实例实际上充当了参数缓冲区; 你是为了方便而交易内存(使用Statement实例代替你自己的外部参数设置缓冲区).

同样,只要我们不讨论特定的 JDBC驱动程序,您应该将这些答案视为一般和推测.每个驱动程序的复杂程度各不相同,每个驱动程序的优化程度各不相同.


Boh*_*ian 15

批次将"一次性完成" - 这就是你要求它做的事情.

在一次通话中尝试50,000似乎有点大.我会将其分解为1000个较小的块,如下所示:

final int BATCH_SIZE = 1000;
for (int i = 0; i < DATA_SIZE; i++) {
  statement.setString(1, "a@a.com");
  statement.setLong(2, 1);
  statement.addBatch();
  if (i % BATCH_SIZE == BATCH_SIZE - 1)
    statement.executeBatch();
}
if (DATA_SIZE % BATCH_SIZE != 0)
  statement.executeBatch();
Run Code Online (Sandbox Code Playgroud)

50,000行不应超过几秒钟.

  • 谢谢,我将按照你的建议这样做,但这将是我的最后一个选择,我在JDBC API中寻找一些内置功能,我可以设置某种批量大小,就像我们在批量阅读时设置Fetch-Size一样,如果没有那么是什么原因没有为批量执行提供批量大小但是允许FetchSize进行批量阅读 (2认同)