Mysql 批量修改四种方式效率对比(一)

2023-05-16

文章目录

  • Mysql 批量修改四种方式效率对比
    • 环境信息
    • 测试数据
      • pom 依赖
      • 数据库
      • 初始化测试数据
    • 批量修改方案
      • 第一种 for
      • 第二种 case when
      • 第三种 replace into
      • 第四种 ON DUPLICATE KEY UPDATE
    • 测试代码
    • 效率比较
    • 总结

Mysql 批量修改四种方式效率对比

环境信息

mysql-5.7.12

mac pro

idea(分配最大内存2g)

测试数据

pom 依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

    </dependencies>

数据库

CREATE TABLE `people` (
  `id` bigint(8) NOT NULL AUTO_INCREMENT,
  `first_name` varchar(50) NOT NULL DEFAULT '',
  `last_name` varchar(50) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

初始化测试数据

    //初始化10w数据
    @Test
    void init10wData() {
        for (int i = 0; i < 100000; i++) {
            People people = new People();
            people.setFirstName(UUID.randomUUID().toString());
            people.setLastName(UUID.randomUUID().toString());
            peopleDAO.insert(people);
        }
    }

批量修改方案

第一种 for

    <!-- 批量更新第一种方法,通过接收传进来的参数list进行循环着组装sql -->
    <update id="updateBatch" parameterType="java.util.List">
        <foreach collection="list" item="item" index="index" open="" close="" separator=";">
            update people
            <set>
                <if test="item.firstName != null">
                    first_name = #{item.firstName,jdbcType=VARCHAR},
                </if>
                <if test="item.lastName != null">
                    last_name = #{item.lastName,jdbcType=VARCHAR},
                </if>
            </set>
            where id = #{item.id,jdbcType=BIGINT}
        </foreach>
    </update>

第二种 case when

    <!-- 批量更新第二种方法,通过 case when语句变相的进行批量更新 -->
    <update id="updateBatch2" parameterType="java.util.List">
        update people
        <trim prefix="set" suffixOverrides=",">
            <trim prefix="first_name = case" suffix="end,">
                <foreach collection="list" item="i" index="index">
                    <if test="i.firstName!=null">
                        when id=#{i.id} then #{i.firstName}
                    </if>
                </foreach>
            </trim>
            <trim prefix="last_name = case" suffix="end,">
                <foreach collection="list" item="i" index="index">
                    <if test="i.lastName!=null">
                        when id=#{i.id} then #{i.lastName}
                    </if>
                </foreach>
            </trim>
        </trim>
        where id in
        <foreach collection="list" index="index" item="item" separator="," open="(" close=")">
            #{item.id,jdbcType=BIGINT}
        </foreach>
    </update>

第三种 replace into

<!-- 批量更新第三种方法,通过 replace into  -->
<update id="updateBatch3" parameterType="java.util.List">
    replace into people
    (id,first_name,last_name) values
    <foreach collection="list" index="index" item="item" separator=",">
        (#{item.id},
        #{item.firstName},
        #{item.lastName})
    </foreach>
</update>

第四种 ON DUPLICATE KEY UPDATE

    <!-- 批量更新第四种方法,通过 duplicate key update  -->
    <update id="updateBatch4" parameterType="java.util.List">
        insert into people
        (id,first_name,last_name) values
        <foreach collection="list" index="index" item="item" separator=",">
            (#{item.id},
            #{item.firstName},
            #{item.lastName})
        </foreach>
        ON DUPLICATE KEY UPDATE
        id=values(id),first_name=values(first_name),last_name=values(last_name)
    </update>

测试代码

/**
 * PeopleDAO继承基类
 */
@Mapper
@Repository
public interface PeopleDAO extends MyBatisBaseDao<People, Long> {

    void updateBatch(@Param("list") List<People> list);

    void updateBatch2(List<People> list);

    void updateBatch3(List<People> list);

    void updateBatch4(List<People> list);
}
    @Test
    void updateBatch() {
        List<People> list = new ArrayList<>();
        int loop = 100;
        int count = 100000;
        Long maxCost = 0L;//最长耗时
        Long minCost = Long.valueOf(Integer.MAX_VALUE);//最短耗时
        System.out.println("开始");
        Long startTime = System.currentTimeMillis();

        for (int j = 0; j < count; j++) {
            People people = new People();
            people.setId(ThreadLocalRandom.current().nextLong(0, 100000));
            people.setFirstName(UUID.randomUUID().toString());
            people.setLastName(UUID.randomUUID().toString());
            list.add(people);
        }

        for (int i = 0; i < loop; i++) {
            Long curStartTime = System.currentTimeMillis();
            peopleDAO.updateBatch4(list);
            Long curCostTime = System.currentTimeMillis() - curStartTime;
            if (maxCost < curCostTime) {
                maxCost = curCostTime;
            }
            if (minCost > curCostTime) {
                minCost = curCostTime;
            }
            System.out.println("耗时-" + (System.currentTimeMillis() - curStartTime));
        }
        System.out.println("结束");
        System.out.println("平均-" + (System.currentTimeMillis() - startTime) / loop + "ms");
        System.out.println("最小-" + minCost + "ms");
        System.out.println("最大-" + maxCost + "ms");
    }

效率比较

数据量forcase whenreplace intoON DUPLICATE KEY UPDATE
500100次
平均-225ms
最小-110ms
最大-907ms
100次
平均-85ms
最小-31ms
最大-1118ms
100次
平均-47ms
最小-23ms
最大-649ms
100次
平均-50ms
最小-21ms最大-933ms
1000100次
平均-371ms
最小-276ms
最大-1178ms
100次
平均-142ms
最小-83ms
最大-877ms
100次
平均-64ms
最小-25ms
最大-658ms
100次
平均-63ms
最小-23ms
最大-649ms
5000100次
平均-1744ms
最小-1296ms
最大-3906ms
100次
平均-3657ms
最小-2606ms
最大-6437ms
100次
平均-286ms
最小-126ms
最大-1105ms
100次
平均-300ms
最小-131ms
最大-1490ms
1000010
平均-3444ms
最小-2433ms
最大-5688ms
10
平均-12898ms最小-10929ms最大-14207ms
100次
平均-365ms
最小-267ms
最大-1409ms
100次
平均-335ms
最小-258ms
最大-1475ms
5000010
平均-17761ms
最小-11305ms
最大-24575ms
卡死不动100次
平均-1810ms
最小-1372ms
最大-3705ms
100次
平均-1923ms
最小-1323ms
最大-5008ms
10000010
平均-31137ms
最小-27493ms
最大-34235ms
卡死不动100次
平均-3249ms
最小-2713ms
最大-5582ms
100次
平均-3079ms
最小-2781ms
最大-6199ms

总结

sql语句for循环效率其实相当高的,因为它仅仅有一个循环体,只不过最后update语句比较多,量大了就有可能造成sql阻塞。

case when虽然最后只会有一条更新语句,但是xml中的循环体有点多,每一个case when 都要循环一遍list集合,所以大批量拼sql的时候会比较慢,所以效率问题严重。使用的时候建议分批插入。

duplicate key update可以看出来是最快的,但是一般大公司都禁用,公司一般都禁止使用replace into和INSERT INTO … ON DUPLICATE KEY UPDATE,这种sql有可能会造成数据丢失和主从上表的自增id值不一致。而且用这个更新时,记得一定要加上id,而且values()括号里面放的是数据库字段,不是java对象的属性字段

参考文章:

mybatis批量更新数据三种方法效率对比 https://blog.csdn.net/q957967519/article/details/88669552

MySql中4种批量更新的方法 https://blog.csdn.net/weixin_42290280/article/details/89384741

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Mysql 批量修改四种方式效率对比(一) 的相关文章

随机推荐

  • C++ 程序编译过程:从代码到程序

    在大学课堂上学习 C 43 43 时 xff0c 老师并没有过多涉猎 C 43 43 语法背后的知识 也就是说 xff0c 初学 C 43 43 时 xff0c 哪怕写出了代码 xff0c 我也并不知道从代码到程序的过程中究竟发生了什么 我
  • 05-STM32F1 - 串行通信1-UART(3),printf,scanf重定向

    05 STM32F1 串行通信UART xff0c printf xff0c scanf重定向 在C 语言标准库中 xff0c fputc 函数是printf 函数内部的一个函数 xff0c 功能是将字符ch 写入到文件指针file所指向文
  • 指针作为函数参数 进行内存释放 并置NULL

    author xff1a 张继飞 写在前面 xff0c 前面写了代码封装free函数 xff0c 但是调用封装并退出后 xff0c 指针并不为NULL xff0c 导致接下来以此作为判断条件的时候就出现问题了 先前封装函数为void fre
  • R40 gpio 寄存器地址操作【原创】

    首先要学会看手册 xff0c 下面拿PC来做说明 3 18 3 Register List Module Name Base Address PIO 0x01C20800 Register Name Offset Description P
  • 关于basic认证和digest认证的初步理解

    1 basic认证是把用户和密码通过base64加密后发送给服务器进行验证 2 digest认证则是把服务器响应的401消息里面的特定的值和用户名以及密码结合起来进行不可逆的摘要算法运算得到一个值 xff0c 然后把用户名和这个摘要值发给服
  • STM32中USART的使用方法

    USART作为一种标准接口在应用中十分常见 本文着重分析其作为 UART的配置和应用方法 1 STM32固件库使用外围设备的主要思路 在 STM32中 xff0c 外围设备的配置思路比较固定 首先是使能相关的时钟 xff0c 一方面是设备本
  • 利用 __FILE__, __LINE__输出debug信息

    include lt stdio h gt define DEBUG ifdef DEBUG define DEBUG format printf 34 File 34 FILE 34 Line 05d 34 format 34 n 34
  • 认证、授权、鉴权和权限控制

    原文地址 https www cnblogs com badboyh2o p 11068779 html 如有侵权 xff0c 请联系删除 xff0c 谢谢 xff01 本文将对信息安全领域中认证 授权 鉴权和权限控制这四个概念给出相应的定
  • 网络编程进阶:并发编程之多线程

    多线程 xff1a 在传统操作系统中 xff0c 每个进程有一个地址空间 xff0c 而且默认就有一个控制线程 xff1b 进程的作用就是隔离数据 进程只是用来把资源集中到一起 xff08 进程只是一个资源单位 xff0c 或者说资源集合
  • subprocess 使用执行 cmd

    参考 Python模块之subprocess用法实例详解 腾讯云开发者社区 腾讯云 上面这个链接主要说了一些用法 补充 通用示例 先来看一个的用法 xff0c 执行 ls 命令 xff0c 返回结果 xff0c 没有报错 xff0c 执行完
  • 多旋翼无人机小知识

    https blog csdn net np4rHI455vg29y2 article details 78954871 根据牛顿第三定律 xff0c 旋翼在旋转的同时 xff0c 也会同时向电机施加一个反作用力 xff08 反扭矩 xff
  • RTK

    实时动态技术 xff08 英语 xff1a Real Time Kinematic xff0c RTK xff09 是实时动态载波相位差分技术的简称 xff0c 是一种通过基准站和流动站的同步观测 xff0c 利用载波相位观测值实现快速高精
  • github Tags和Branch分支相关操作(三)

    Tag推送 1 git查看tag命令 xff1a git tag 2 创建Tag直接加入名字就好了 xff0c 格式 xff1a git tag 名字 m 注释 这时只能在本地可以看到自己新建Tag xff0c 在远程中央仓库中还是看不到在
  • PostMan中文汉化亲测好用!!!!

    PostMan 中文汉化版 最新版本 xff1a 8 10 0 更新时间 xff1a 2021 08 07 请认真阅读存储库的自述文件README md 汉化包下载链接 https github com hlmd Postman cn re
  • ubuntu下安装多个版本的python

    本身系统安装了python2 7和python3 5 现在由于开发需要 xff0c 还需要安装python3 6 安装步骤如下 xff1a 1 下载 Python 直接在官网下载 Python的源代码 xff0c 解压缩 xff0c 按照
  • stm32标准库文件内容说明

    目录 思维导图 一 stm32f4xx h文件内容说明 1 定义了HSE时钟频率的值 2 定义了启动HSE时钟的超时时间 xff0c HSI时钟频率的值 3 根据不同的芯片定义中断向量表结构体 4 包含一些头文件 5 对一些数据类型进行重命
  • UART协议详解

    UART使用的是 异步 xff0c 串行通信 串行通信是指利用一条传输线将资料一位位地顺序传送 特点是通信线路简单 xff0c 利用简单的线缆就可实现通信 xff0c 降低成本 xff0c 适用于远距离通信 xff0c 但传输速度慢的应用场
  • C++中的.和::和:和-」的区别

    转自 xff1a https blog csdn net liao392781 article details 97931845 在学习C 43 43 的过程中我们经常会用到 和 和 xff1a 和 gt xff0c 在此整理一下这些常用符
  • hpsocket实现HTTP通信功能

    前段时间朋友急需让我帮忙搞定个C 43 43 的http库 xff1f xff1f xff1f xff1f 然后指定了hpsocket这个库 看了一下是国人写了 xff0c 资料在doc还算比较全 xff0c 整理了很多框架的部分也挺详细
  • Mysql 批量修改四种方式效率对比(一)

    文章目录 Mysql 批量修改四种方式效率对比环境信息测试数据pom 依赖数据库初始化测试数据 批量修改方案第一种 for第二种 case when第三种 replace into第四种 ON DUPLICATE KEY UPDATE 测试