批量更新的两种方式效率对比

一种用for循环,循环出N条update语句,

另一种用 case when 循环出一个长sql语句

方式一:拼接多个update

<update id="updateBatch" parameterType="java.util.List">
        <foreach collection="list" item="item" separator=";">
            UPDATE table_test
            SET
            container_id = #{item.containerId,jdbcType=BIGINT},
            ...省略其他字段
        </foreach>
</update>

运行起来的样子(其实就是多个update语句以 ;分隔,一次性传输给数据库执行)

UPDATE table_test SET container_id = 4163823751071650816 .... WHERE container_id = 4163823751071650816 ; 

UPDATE table_test SET container_id = 7159856530952156160 .... WHERE container_id = 7159856530952156160 ; 

......

方式二:case when 拼接成一个长长的sql语句

<update id="batchModifyBoolAttrInfo">
    update table_test 
    <!-- 拼接case when 每多一个字段,需要多一个循环 -->
    <trim prefix="set" suffixOverrides=",">
        <trim prefix="bool_attr_info =case" suffix="end,">
            <foreach collection="list" item="item" index="index">
                when container_id = #{item.containerId} then 1024
            </foreach>
        </trim>
    </trim>
    ...省略其他字段
    where container_id in
    <foreach collection="list" index="index" item="item" separator="," open="("            
        close=")"> #{item.containerId} 
    </foreach>
</update>

准备测试

String sql = "select * from table_test where name = 'TEST' limit 2000";
List<ContainerInfo> containerInfos = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(ContainerInfo.class));
containerInfos.forEach(a -> a.setBoolAttrInfo(2048L));
StopWatch stopWatch = new StopWatch();
stopWatch.start();
containerDao.updateBatch2(containerInfos);
stopWatch.stop();
System.out.printf("执行时长: %d 毫秒",stopWatch.getTotalTimeMillis());

以下是测试3次更新5个字段的值在  2000条,1000条,500条,100条 时各自的耗时对比:

updateBatchcase when长语句
2000条

5.8s  6.9s  5.9s    

16s   17s   16s

1000条

2.9s  2.3s  2.3s

5.7s  7.0s  7.7s

500条

0.85s  0.76s  1.2s

1.48s  1.50s  1.50s

100条

0.19s  0.1s  0.1s

0.32s  0.1s  0.1s

可以看到 case when 效率是低于 updateBatch 的,原因在于 updateBatch 更新无论更新几个字段都只有一个循环体 foreach,而 case when 每多更新一个字段,就要多一个循环体去拼接sql

<trim prefix="bool_attr_info =case" suffix="end,">
    <foreach collection="list" item="item" index="index">
        when container_id = #{item.containerId} then 1024
    </foreach>
</trim>
<trim prefix="c_group_code =case" suffix="end,">
    <foreach collection="list" item="item" index="index">
        when container_id = #{item.containerId} then '2023'
    </foreach>
</trim>
......            

但当更新的字段减少时,case when的效率又会反超 updateBatch,如下是更新2000条记录,一个字段和两个字段的耗时:

updateBatchcase when长语句
两个字段

3.5s  3.0s   3.4s

5s  7s  5.5s

一个字段

2.8s  3.5s  2.6s

1.6s   1.4s   1.5s

结论:case when的效率受制于循环体的个数,当循环体的数量最少即只更新一个字段时,case when的速度要快于updateBatch批处理,其他情况还是使用updateBatch批处理的方式更快。

另外:这两种方式都需要控制参数的个数,否则会造成异常,比如一个表有65个字段,而我一次性更新65个字段并且记录数超过2000,就会有12万个参数,导致异常。

PreparedStatement can have at most 65,535 parameters. 
Please consider using arrays, or splitting the query in several ones, 
or using COPY. Given query has 121,600 parameters

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以使用MySQL的循环语句和UPDATE语句来实现循环更新。以下是一个简单的示例: ``` DELIMITER $$ CREATE PROCEDURE update_loop() BEGIN DECLARE i INT DEFAULT 1; DECLARE n INT; SELECT COUNT(*) FROM your_table INTO n; WHILE i <= n DO UPDATE your_table SET column_name = new_value WHERE id = i; SET i = i + 1; END WHILE; END $$ DELIMITER ; -- 执行存储过程 CALL update_loop(); ``` 上述代码中,首先创建了一个存储过程`update_loop()`,该过程中使用了`DECLARE`语句声明了两个变量`i`和`n`,并将`n`设置为表中记录的数量。然后使用`WHILE`循环语句,依次将每条记录的指定列更新为新的值,最后将`i`加1,直到所有记录都被更新完毕。最后,使用`CALL`语句调用该存储过程即可实现循环更新。 ### 回答2: MySQL循环更新是指在一个查询中重复执行更新操作,可以通过循环更新语句来批量修改数据库中的数据。在MySQL中,可以使用循环遍历匹配条件并逐一更新数据。 首先,我们需要创建一个循环来重复执行更新操作。MySQL中可以使用循环语句如WHILE或REPEAT来实现循环。具体操作如下: 1. 创建循环变量和结束变量,用于控制循环的条件和结束条件。 2. 使用循环语句来重复执行更新操作。可以使用UPDATE语句来更新满足条件的数据,同时使用LIMIT子句来限制每次更新的记录数量,以免造成性能问题。 3. 在循环更新完数据后,需要对循环变量进行自增或更新结束条件。 4. 当循环结束时,退出循环。 以下是一个简单的示例:假设我们有一个students表,其中有id和score两个字段,我们要批量将分数小于60的学生的分数更新为60。 ``` DELIMITER // CREATE PROCEDURE update_scores() BEGIN DECLARE done INT DEFAULT FALSE; DECLARE student_id INT; DECLARE student_score INT; DECLARE cur CURSOR FOR SELECT id, score FROM students WHERE score < 60; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; OPEN cur; read_loop: LOOP FETCH cur INTO student_id, student_score; IF done THEN LEAVE read_loop; END IF; UPDATE students SET score = 60 WHERE id = student_id; END LOOP; CLOSE cur; END // DELIMITER ; CALL update_scores(); ``` 通过以上的示例代码,我们可以通过循环更新语句来批量修改满足条件的数据。当然,循环更新涉及到数据库操作,需要谨慎使用,以免对性能产生不利影响。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值