在 MyBatis 中使用输入参数 List<T> 将大量行更新到 Oracle db 的最快方法
Fastest way to update huge number of rows with input param List<T> in MyBatis to Oracle db
我通过将 MyBatis 中的变量列表传递给 Oracle DB 来更新大量数据。
这个 link 的方法对我来说不够有效,逐行提交更新 sql 查询的方法,sql 查询或 Executor.batch 中的循环服务比我预期的要慢。
//one of the method i use
<update id="updateAll">
BEGIN
<foreach collection="list" item="item" index="index" separator=";">
UPDATE <include refid="tableName"/>
<set>
item_price = ${item.price}, update_time = ${item.updateTime}
</set>
WHERE id = ${item.id}
</foreach>
;END;
</update>
按照我尝试过的方式,我的系统需要 10 - 30 秒或更长时间才能完成更新。服务器每秒将有大约 10,000 行数据。有什么方法可以在 Oracle 数据库中在 1 或 2 秒内更新至少 1-2k 行数据?
使用批处理程序是推荐的方式,但你需要正确地使用它。
我注意到的两个问题。
- 设置合适的批量大小很重要。 linked answer最后发送所有数据,效率很低。
- 使用
${}
引用参数使每个语句都是唯一的,并防止驱动程序重复使用该语句(基本上失去了批处理执行器的好处)。 #{}
和 ${}
的区别见 this FAQ。
下面是典型的使用MyBatis的批处理操作
由于最佳 batchSize
取决于多种因素,您应该使用实际数据来衡量性能。
int batchSize = 1000;
try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) {
YourMapper mapper = sqlSession.getMapper(YourMapper.class);
int size = list.size();
for (int i = 0; i < size;) {
mapper.update(list.get(i));
i++;
if (i % batchSize == 0 || i == size) {
sqlSession.flushStatements();
sqlSession.clearCache();
}
}
sqlSession.commit();
}
这里是更新语句的高效版本。
<update id="update">
UPDATE <include refid="tableName" />
SET
item_price = #{item.price},
update_time = #{item.updateTime}
WHERE id = #{item.id}
</update>
我通过将 MyBatis 中的变量列表传递给 Oracle DB 来更新大量数据。
这个 link 的方法对我来说不够有效,逐行提交更新 sql 查询的方法,sql 查询或 Executor.batch 中的循环服务比我预期的要慢。
//one of the method i use
<update id="updateAll">
BEGIN
<foreach collection="list" item="item" index="index" separator=";">
UPDATE <include refid="tableName"/>
<set>
item_price = ${item.price}, update_time = ${item.updateTime}
</set>
WHERE id = ${item.id}
</foreach>
;END;
</update>
按照我尝试过的方式,我的系统需要 10 - 30 秒或更长时间才能完成更新。服务器每秒将有大约 10,000 行数据。有什么方法可以在 Oracle 数据库中在 1 或 2 秒内更新至少 1-2k 行数据?
使用批处理程序是推荐的方式,但你需要正确地使用它。
我注意到的两个问题。
- 设置合适的批量大小很重要。 linked answer最后发送所有数据,效率很低。
- 使用
${}
引用参数使每个语句都是唯一的,并防止驱动程序重复使用该语句(基本上失去了批处理执行器的好处)。#{}
和${}
的区别见 this FAQ。
下面是典型的使用MyBatis的批处理操作
由于最佳 batchSize
取决于多种因素,您应该使用实际数据来衡量性能。
int batchSize = 1000;
try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) {
YourMapper mapper = sqlSession.getMapper(YourMapper.class);
int size = list.size();
for (int i = 0; i < size;) {
mapper.update(list.get(i));
i++;
if (i % batchSize == 0 || i == size) {
sqlSession.flushStatements();
sqlSession.clearCache();
}
}
sqlSession.commit();
}
这里是更新语句的高效版本。
<update id="update">
UPDATE <include refid="tableName" />
SET
item_price = #{item.price},
update_time = #{item.updateTime}
WHERE id = #{item.id}
</update>