批处理数据主要有三种方式:
- 反复执行单条插入语句
foreach
拼接sql
- 批处理
一、前期准备
基于Spring Boot
+ Mysql
,同时为了省略get
/set
,使用了lombok
,详见pom.xml
。
1.1 表结构
id
使用数据库自增。
1 | sql复制代码DROP TABLE IF EXISTS `user_info_batch`; |
1.2 项目配置文件
细心的你可能已经发现,数据库url
后面跟了一段 rewriteBatchedStatements=true
,有什么用呢?先不急,后面会介绍。
1 | xml复制代码# 数据库配置 |
1.3 实体类
1 | typescript复制代码@Data |
1.4 UserInfoBatchMapper
1 | java复制代码public interface UserInfoBatchMapper { |
1.5 UserInfoBatchMapper.xml
1 | xml复制代码<?xml version="1.0" encoding="UTF-8"?> |
1.6 预备数据
为了方便测试,抽离了几个变量,并进行提前加载。
1 | ini复制代码 private List<UserInfoBatchDO> list = new ArrayList<>(); |
- 为了方便组装数据,抽出了一个公共方法。
1 | csharp复制代码 private List<UserInfoBatchDO> assemblyData(int count){ |
- 预热数据
1 | ini复制代码 @Before |
二、反复执行单条插入语句
可能‘懒’的程序员会这么做,很简单,直接在原先单条
insert
语句上嵌套一个for
循环。
2.1 对应 mapper 接口
1 | arduino复制代码int insert(UserInfoBatchDO info); |
2.2 测试方法
因为这种方法太慢,所以数据降低到
2000
条
1 | scss复制代码@Test |
2.3 执行时间
- 第一次
1 | xml复制代码----------------------------------------- |
- 第二次
1 | xml复制代码----------------------------------------- |
- 第三次
1 | xml复制代码----------------------------------------- |
该方式插入2000
条数据,执行三次的平均时间:60991 ms
。
三、foreach
拼接SQL
3.1 对应mapper 接口
1 | java复制代码int batchInsert(List<UserInfoBatchDO> list); |
3.2 测试方法
该方式和下一种方式都采用
20w
条数据测试。
1 | scss复制代码@Test |
3.3 执行时间
- 第一次
1 | xml复制代码----------------------------------------- |
- 第二次
1 | xml复制代码----------------------------------------- |
- 第三次
1 | xml复制代码----------------------------------------- |
该方式插入20w
条数据,执行三次的平均时间:18852 ms
。
四、批处理
该方式
mapper
和xml
复用了2.1
。
4.1 rewriteBatchedStatements
参数
我在测试一开始,发现改成
Mybatis Batch
提交的方法都不起作用,实际上在插入的时候仍然是一条条记录的插,而且速度远不如原来foreach
拼接SQL
的方法,这是非常不科学的。
后来才发现要批量执行的话,连接URL
字符串中需要新增一个参数:rewriteBatchedStatements=true
rewriteBatchedStatements
参数介绍
MySql
的JDBC
连接的url
中要加rewriteBatchedStatements
参数,并保证5.1.13
以上版本的驱动,才能实现高性能的批量插入。MySql JDBC
驱动在默认情况下会无视executeBatch()
语句,把我们期望批量执行的一组sql
语句拆散,一条一条地发给MySql
数据库,批量插入实际上是单条插入,直接造成较低的性能。只有把rewriteBatchedStatements
参数置为true
, 驱动才会帮你批量执行SQL
。这个选项对INSERT
/UPDATE
/DELETE
都有效。
4.2 批处理准备
- 手动注入
SqlSessionFactory
1 | java复制代码 @Resource |
- 测试代码
1 | ini复制代码@Test |
4.3 执行时间
- 第一次
1 | xml复制代码----------------------------------------- |
- 第二次
1 | xml复制代码----------------------------------------- |
- 第三次
1 | xml复制代码----------------------------------------- |
该方式插入20w
条数据,执行三次的平均时间:9092 ms
。
4.4 如果数据更大
当我把数据扩大到 100w
时,foreach
拼接 sql
的方式已经无法完成插入了,所以我只能测试批处理的插入时间。
测试时,仅需将 【4.2】测试代码中的
list
切成lageList
测试即可。
- 第一次
1 | xml复制代码----------------------------------------- |
- 第二次
1 | xml复制代码----------------------------------------- |
- 第三次
1 | xml复制代码----------------------------------------- |
该方式插入100w
条数据,执行三次的平均时间:32467 ms
。
五、总结
批量插入方式 | 数据量 | 执行三次的平均时间 |
---|---|---|
循环插入单条数据 | 2000 | 60991 ms |
foreach 拼接sql |
20w | 18852 ms |
批处理 | 20w | 9092 ms |
批处理 | 100w | 32467 ms |
- 循环插入单条数据虽然效率极低,但是代码量极少,数据量较小时可以使用,但是数据量较大禁止使用,效率太低了;
foreach
拼接sql
的方式,使用时有大段的xml和sql语句要写,很容易出错,虽然效率尚可,但是真正应对大量数据的时候,依旧无法使用,所以不推荐使用;- 批处理执行是有大数据量插入时推荐的做法,使用起来也比较方便。
【本文示例代码】
1 | 复制代码 |
本文转载自: 掘金