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

时间:2011-07-31 20:28:30

标签: java resultset bulkinsert prepared-statement

我试图在Java中用大约50,000行10列填充resultSet 然后使用batchExecute的{​​{1}}方法将它们插入到另一个表中。

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

fetchSize非常低可能导致到服务器的次数过多,而fetchSize非常高可能会阻塞网络资源,因此我尝试了一点并设置了适合我的基础设施的最佳大小。

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

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

PreparedStatement
  • executeBatch方法是否会尝试一次发送所有数据?
  • 有没有办法定义批量大小?
  • 有没有更好的方法来加快批量插入过程?

批量更新(50,000行10个字符串)时,使用可更新的for (i=0 ; i<=50000 ; i++) { statement.setString(1, "a@a.com"); statement.setLong(2, 1); statement.addBatch(); } statement.executeBatch(); 或PreparedStaement批量执行是否更好?

4 个答案:

答案 0 :(得分:45)

我将依次解决您的问题。

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

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

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

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

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

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

此建议假定您的插入不会与并发编写者竞争,并假定这些事务边界将为您提供从源表中读取的足够一致的值,以便在插入中使用。如果情况并非如此,那么赞成正确而不是速度。

  • 在批处理执行中使用可更新ResultSetPreparedStatement是否更好?

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

同样,只要我们不讨论特定的 JDBC驱动程序,您应该认为这些答案是通用的和推测性的。每个驱动程序的复杂程度各不相同,每个驱动程序的优化程度各不相同。

答案 1 :(得分:14)

批次将以“一次性完成”完成 - 这就是你要求它做的。

在一次通话中尝试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();

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

答案 2 :(得分:1)

如果只是数据库中一个/多个表中的数据要插入此表而没有干预(对结果集的更改),则调用statement.executeUpdate(SQL)执行{{3由于没有开销,因此速度更快。没有数据流出数据库,整个操作都在数据库上而不是应用程序中。

答案 3 :(得分:0)

批量未记录更新不会为您提供所需的改进性能。见this