对 MyBatis Plus SaveBatch 调优提升25倍性能!!!

简介: 最近在压测一批接口,发现接口处理速度慢的有点超出预期,感觉很奇怪,后面定位发现是数据库批量保存这块很慢。这个项目用的是,批量保存直接用的是提供的 saveBatch。于是开始排查之路。所以如果有使用 jdbc 的 Batch 性能方面的需求,要将rewriteBatchedStatements 设置为 true,这样能提高很多性能。然后如果喜欢手动拼接 sql 要注意一次拼接的数量,分批处理。

 其他系列文章导航

Java基础合集

数据结构与算法合集

设计模式合集

多线程合集

分布式合集

ES合集


文章目录

其他系列文章导航

文章目录

前言

一、源码分析

二、优化过程

三、疑问

四、总结


前言

最近在压测一批接口,发现接口处理速度慢的有点超出预期,感觉很奇怪,后面定位发现是数据库批量保存这块很慢。

这个项目用的是 mybatis-plus,批量保存直接用的是 mybatis-plus 提供的 saveBatch。

于是开始排查之路。


一、源码分析

我点进去看了下源码,感觉有点不太对劲。

如下图所示:

image.gif编辑

我继续追踪了下,从这个代码来看,确实是 for 循环一条一条执行了 sqlSession.insert,下面的 consumer 执行的就是上面的 sqlSession.insert。

如下图所示:

image.gif编辑

然后累计一定数量后,一批 flush。

从这点来看,这个 saveBach 的性能肯定比直接一条一条 insert 快。

拼接 sql 的方式实现批量保存效率最佳。

但是我又不太甘心,总感觉应该有什么别的法子,然后我就继续跟着 mybatis-plus 的源码 debug 了一下,跟到了 mysql 的驱动,突然发现有个 if 里面的条件有点显眼。

如下图所示:

image.gif编辑

就是这个叫 rewriteBatchedStatements 的玩意,从名字来看是要重写批操作的 Statement,前面batchHasPlainStatements 已经是 false,取反肯定是 true,所以只要这参数是 true 就会进行一波操作。

我看了下默认是 false。

如下图所示:

image.gif编辑


二、优化过程

同时我也上网查了下 rewriteBatchedStatements 参数,好家伙,好像有用!

image.gif编辑

我直接将 jdbcurl 加上了这个参数。

如下图所示:

image.gif编辑

然后继续跑了下 mybatis-plus 自带的 saveBatch,果然性能大大提高,跟拼接 SQL 差不多!

如下图所示:

image.gif编辑

顺带我也跑了下 JDBC 的 executeBatch ,果然也提高了。

如下图所示:

image.gif编辑

然后我继续 debug ,来探探 rewriteBatchedStatements 究竟是怎么 rewrite 的!

如果这个参数是 true,则会执行下面的方法且直接返回。

如下图所示:

image.gif编辑

看下 executeBatchedInserts 究竟干了什么?

如下图所示:

image.gif编辑

看到上面我圈出来的代码没,好像已经有点感觉了,继续往下 debug。

果然!sql 语句被 rewrite了!!!

如下图所示:

image.gif编辑

对插入而言,所谓的 rewrite 其实就是将一批插入拼接成 insert into xxx values (a),(b),(c)...这样一条语句的形式然后执行,这样一来跟拼接 sql 的效果是一样的。


三、疑问

那为什么默认不给这个参数设置为 true 呢?

我简单问了下 ChatGPT:

    1. 如果批量语句中的某些语句失败,则默认重写会导致所有语句都失败。
    2. 批量语句的某些语句参数不一样,则默认重写会使得查询缓存未命中。

    看起来影响不大,所以我给我的项目设置上了这个参数!

    稍微总结下我粗略的对比(虽然粗略,但实验结果符合原理层面的理解),如果你想更准确地实验,可以使用JMH,并且测试更多组数(如 5000,10000等)的情况。

    批量保存方式 数据量(条) 耗时(ms)
    单条循环插入 1000 121011
    mybatis-plus saveBatch 1000 59927
    mybatis-plus saveBatch(添加rewtire参数) 1000 2589
    手动拼接sql 1000 2275
    jdbc executeBatch 1000 55663
    jdbc executeBatch(添加rewtire参数) 1000 324

    四、总结

    所以如果有使用 jdbc 的 Batch 性能方面的需求,要将 rewriteBatchedStatements 设置为 true,这样能提高很多性能。

    然后如果喜欢手动拼接 sql 要注意一次拼接的数量,分批处理。

    目录
    相关文章
    |
    2月前
    |
    Java 关系型数据库 数据库连接
    MyBatis Plus 解决大数据量查询慢问题
    MyBatis Plus 解决大数据量查询慢问题
    |
    2月前
    |
    druid Java 数据库连接
    Spring Boot3整合MyBatis Plus
    Spring Boot3整合MyBatis Plus
    46 1
    |
    2月前
    |
    Java 数据库连接 mybatis
    mybatis plus字段为null或空字符串把原来的数据也更新了,只需要注解
    mybatis plus字段为null或空字符串把原来的数据也更新了,只需要注解
    22 0
    |
    2月前
    |
    Java 数据库连接 数据库
    Spring Boot整合MyBatis Plus集成多数据源轻松实现数据读写分离
    Spring Boot整合MyBatis Plus集成多数据源轻松实现数据读写分离
    28 2
    |
    2月前
    |
    存储 缓存 Java
    什么!?实战项目竟然撞到阿里面试的原题!???关于MyBatis Plus的缓存机制
    什么!?实战项目竟然撞到阿里面试的原题!???关于MyBatis Plus的缓存机制
    |
    2月前
    |
    缓存 Java 数据库连接
    MyBatis Plus的“幻查” 规范到底要怎样使用哪几个查询函数 为什么会出现幻查?还有幻删为什么会删不掉
    MyBatis Plus的“幻查” 规范到底要怎样使用哪几个查询函数 为什么会出现幻查?还有幻删为什么会删不掉
    |
    4月前
    |
    SQL Java 数据库连接
    快速上手MyBatis Plus:简化CRUD操作,提高开发效率!
    快速上手MyBatis Plus:简化CRUD操作,提高开发效率!
    |
    4月前
    |
    Java 数据库连接 数据库
    Spring Boot整合Mybatis Plus[极简教程]
    Spring Boot整合Mybatis Plus[极简教程]
    60 0
    |
    4月前
    |
    Java 数据库连接 测试技术
    使用lambdaQuery进行条件查询的MyBatis Plus案例
    使用lambdaQuery进行条件查询的MyBatis Plus案例
    382 0