两种 JDBC 查询批处理方法中哪一种更快?
Which of the two JDBC query batching approaches is faster?
我正在尝试 运行 在具有数百万条记录的 table 上使用 rownum 分批更新语句。
第一种方法是将所有查询一起批处理,然后 运行ning executeBatch()
方法如下,
for (i = num; i < limit; i += num) {
String query = "update Table set someColumn ='T' where rownum<=" + i;
preparedStatement = dbConnection.prepareStatement(query);
preparedStatement.addBatch();
}
preparedStatement.executeBatch();
dbConnection.commit();
第二种方法是 运行 一个批量更新语句并在每批之后提交,如下所示,
String query = "update Table set someColumn ='T' where rownum<=?";
preparedStatement = dbConnection.prepareStatement(query);
int count = 1;
while (count > 0) {
preparedStatement.setInt(1, num);
count = preparedStatement.executeUpdate();
dbConnection.commit();
}
我认为第二种方法更简洁,因为它在每批之后提交,但是第一种方法比第二种方法花费的时间少得多。
谁能给我解释一下为什么会这样?或者如果我的方法和理解有任何错误。
使用一批。
逻辑原因:
除非你的提交大小的高水位线超过你服务器的日志限制(在这种情况下你的事务将在中途回滚),你可能需要 all语句成功完成,或 all 失败。解开部分数据库更新要困难得多,并且(取决于您的情况)如果只有一些更新成功,您可能会使数据处于不一致状态。
性能原因:
允许数据库优化解析一个命令,协调所有活动,只启动一个事务,只进行一次提交。
对同一准备语句的不同绑定变量使用批处理:
String query = "update Table set someColumn ='T' where rownum<=?";
preparedStatement = dbConnection.prepareStatement(query);
for (i = num; i < limit; i += num) {
preparedStatement.setInt(1, num);
count = preparedStatement.addBatch();
}
preparedStatement.executeBatch();
dbConnection.commit();
Can someone explain to me why this is so?
这里有很多不同的东西可以优化:
- JDBC/ODBC 驱动程序和数据库引擎为准备和
解析语句
- 客户端和数据库服务器之间的往返流量
- 数据库引擎打开和关闭所做的工作(即提交
或回滚)事务
你的例子正在优化不同的东西:
- 通过使用绑定参数(如您的第二个示例),您只需
准备语句一次,这减少了
ODBC/JDBC 驱动程序,可能还有数据库引擎。
- 通过减少批处理的执行次数(第一个示例),您正在减少
客户端和服务器之间的往返次数。
- 通过减少提交次数(又是第一个示例),您正在减少提交次数
数据库需要打开和关闭事务的次数。
如您所见,瓶颈原来是打开和关闭事务的开销。多次往返也无济于事。这些比不使用绑定参数的成本更高。
令人高兴的是,在此示例中,您可以优化所有三件事。您可以使用绑定参数,一次将所有命令发送到数据库,然后执行一次提交。请参阅 Jean de Lavarene 的回答。
但请注意行为的变化:如果您在单个批次中提交,一个错误将导致批次中的所有内容回滚。这可能正是您想要的,但如果不是,这些考虑可能优先于性能。
我正在尝试 运行 在具有数百万条记录的 table 上使用 rownum 分批更新语句。
第一种方法是将所有查询一起批处理,然后 运行ning executeBatch()
方法如下,
for (i = num; i < limit; i += num) {
String query = "update Table set someColumn ='T' where rownum<=" + i;
preparedStatement = dbConnection.prepareStatement(query);
preparedStatement.addBatch();
}
preparedStatement.executeBatch();
dbConnection.commit();
第二种方法是 运行 一个批量更新语句并在每批之后提交,如下所示,
String query = "update Table set someColumn ='T' where rownum<=?";
preparedStatement = dbConnection.prepareStatement(query);
int count = 1;
while (count > 0) {
preparedStatement.setInt(1, num);
count = preparedStatement.executeUpdate();
dbConnection.commit();
}
我认为第二种方法更简洁,因为它在每批之后提交,但是第一种方法比第二种方法花费的时间少得多。
谁能给我解释一下为什么会这样?或者如果我的方法和理解有任何错误。
使用一批。
逻辑原因:
除非你的提交大小的高水位线超过你服务器的日志限制(在这种情况下你的事务将在中途回滚),你可能需要 all语句成功完成,或 all 失败。解开部分数据库更新要困难得多,并且(取决于您的情况)如果只有一些更新成功,您可能会使数据处于不一致状态。
性能原因:
允许数据库优化解析一个命令,协调所有活动,只启动一个事务,只进行一次提交。
对同一准备语句的不同绑定变量使用批处理:
String query = "update Table set someColumn ='T' where rownum<=?";
preparedStatement = dbConnection.prepareStatement(query);
for (i = num; i < limit; i += num) {
preparedStatement.setInt(1, num);
count = preparedStatement.addBatch();
}
preparedStatement.executeBatch();
dbConnection.commit();
Can someone explain to me why this is so?
这里有很多不同的东西可以优化:
- JDBC/ODBC 驱动程序和数据库引擎为准备和 解析语句
- 客户端和数据库服务器之间的往返流量
- 数据库引擎打开和关闭所做的工作(即提交 或回滚)事务
你的例子正在优化不同的东西:
- 通过使用绑定参数(如您的第二个示例),您只需 准备语句一次,这减少了 ODBC/JDBC 驱动程序,可能还有数据库引擎。
- 通过减少批处理的执行次数(第一个示例),您正在减少 客户端和服务器之间的往返次数。
- 通过减少提交次数(又是第一个示例),您正在减少提交次数 数据库需要打开和关闭事务的次数。
如您所见,瓶颈原来是打开和关闭事务的开销。多次往返也无济于事。这些比不使用绑定参数的成本更高。
令人高兴的是,在此示例中,您可以优化所有三件事。您可以使用绑定参数,一次将所有命令发送到数据库,然后执行一次提交。请参阅 Jean de Lavarene 的回答。
但请注意行为的变化:如果您在单个批次中提交,一个错误将导致批次中的所有内容回滚。这可能正是您想要的,但如果不是,这些考虑可能优先于性能。