批处理 rewriteBatchedStatements=true
项目中有很多批处理,mysql提供了一个参数rewriteBatchedStatements,可以实现高性能的批量插入
MySQL的JDBC连接的url中要加rewriteBatchedStatements参数,并保证5.1.13以上版本的驱动,才能实现高性能的批量插入。
MySQL JDBC驱动在默认情况下会无视executeBatch()语句,把我们期望批量执行的一组sql语句拆散,一条一条地发给MySQL数据库,批量插入实际上是单条插入,直接造成较低的性能。
只有把rewriteBatchedStatements参数置为true, 驱动才会帮你批量执行SQL另外这个选项对INSERT/UPDATE/DELETE都有效
验证
- 准备一个表
CREATE TABLE `t_user` (
`id` bigint(20) NOT NULL,
`user_name` varchar(45) DEFAULT NULL,
`password` varchar(45) DEFAULT NULL,
`nick_name` varchar(45) DEFAULT NULL,
`id_card` varchar(45) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
- 代码,批量插入100000条数据
@GetMapping("/save")
public String save() {
List<User> users = new ArrayList<>();
Random random = new Random();
StopWatch stopWatch = new StopWatch("test");
stopWatch.start("create user");
for (int i = 0; i < 100000; i++) {
User user = new User();
user.setNickName("haha"+i);
user.setIdCard("4304811992"+random.nextInt(10000)+random.nextInt(10000));
user.setPassword(random.nextInt(10000)+"");
user.setCreateTime(new Timestamp(System.currentTimeMillis()));
user.setUpdateTime(new Timestamp(System.currentTimeMillis()));
user.setUserName("xiaohei"+i);
users.add(user);
}
stopWatch.stop();
stopWatch.start("saveBatch");
userService.saveBatch(users);
stopWatch.stop();
System.out.println(stopWatch.prettyPrint());
return "新增用户成功";
}
1. 无rewriteBatchedStatements参数
项目中数据源配置如下,不添加rewriteBatchedStatements参数
spring:
# 配置数据源
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true
username: root
password: root
执行结果
StopWatch 'test': running time = 86006762062 ns
---------------------------------------------
ns % Task name
---------------------------------------------
201687212 000% create user
85805074850 100% saveBatch
2. 有rewriteBatchedStatements参数
项目中数据源配置添加rewriteBatchedStatements参数
spring:
# 配置数据源
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true
username: root
password: root
再次运行
StopWatch 'test': running time = 25266180502 ns
---------------------------------------------
ns % Task name
---------------------------------------------
227148131 001% create user
25039032371 099% saveBatch
结论
jdbc的连接串中使用rewriteBatchedStatements参数,批处理性能提升3倍。
作者:御风_2fd9
链接:https://www.jianshu.com/p/1eeb517c6ce7
来源:简书
总结
批量插入,从事务方面总结
url的参数 jdbc foreach拼接 mybatis-plus
不加 一条insert一条参数 一条insert多条参数(建议1000条参数) 每条insert有1条参数,只提交一次事务
加 一条insert多条参数(建议1000条参数) 一条insert多条参数(建议1000条参数) 每条insert有1000条参数,只提交一次事务
效率总结
数据库和代码都是我本地,基础配置如下
处理器 i7-10510U CPU 1.80GHz
内存16.0 GB
机械硬盘HDD 转速5400转 数据传输速率600M/秒
表有30个字段,每次测试都会清空数据,一条insert按1000条参数来测试
数量/大小 jdbc不加参数 jdbc加 foreach加不加一样 mybatis-plus不加 mybatis-plus加
1万/3.53MB 420秒 2秒 4秒 5秒 5秒
10万/32.58MB 没测 17秒 30秒 35秒 20秒
100万/276.84MB 没测 266秒 455秒 330秒 180秒
实际写入速度请以自己电脑或服务器配置为准。我这个测试没有网络消耗,正常生产环境是有网络消耗的
一万以下
jdbc不加 < mybatis-plus不加 < mybatis-plus加 < foreach < jdbc加
一万到十万
jdbc不加 < mybatis-plus不加 < foreach < mybatis-plus加 < jdbc加
十万到-一百万
jdbc不加 < mybatis-plus不加 < jdbc加 < foreach < mybatis-plus加
mybatis-plus加参数比其他情况还是有所提升的
过了好几个月补的
为了贴近实际,测试了一个有网络消耗的
数据库在内网服务器
java代码再我本地,我连上WiFi来连接数据库
50个字段
数量/大小 foreach加不加一样 mybatis-plus不加 mybatis-plus加
1千/0.33MB 1秒 15秒 0.8秒
1万/3.53MB 4秒 150秒 5秒
mybatis-plus不加 比 foreach |mybatis-plus加 慢15到30倍
        我曾七次鄙视自己的灵魂:
  第一次,当它本可进取时,却故作谦卑;
  第二次,当它在空虚时,用爱欲来填充;
  第三次,在困难和容易之间,它选择了容易;
  第四次,它犯了错,却借由别人也会犯错来宽慰自己;
  第五次,它自由软弱,却把它认为是生命的坚韧;
  第六次,当它鄙夷一张丑恶的嘴脸时,却不知那正是自己面具中的一副;
  第七次,它侧身于生活的污泥中,虽不甘心,却又畏首畏尾。
时间仓促,如有错误欢迎指出,欢迎在评论区讨论,如对您有帮助还请点个推荐、关注支持一下
作者:博客园 - 角刀牛
出处:https://www.cnblogs.com/jiaodaoniujava/
该文章来源互联网,本博仅以学习为目的,版权归原作者所有。
若内容有侵犯您权益的地方,请公告栏处联系本人,本人定积极配合处理解决。