mysql官方文档:rewriteBatchedStatements相关介绍
接下来我们用WWW的方式去了解rewriteBatchedStatements
一、是什么?
rewriteBatchedStatements 是Mysql 3.1.13版本新增的一个设置参数,表示是否启用批量更新重写功能的配置参数,true代表开启,false代表关闭(默认);
网上很多文章说5.1.13以上版本的驱动(存疑),测试5.12版本也可以;过低版本会提示和springboot版本不兼容
二、为什么?
MySQL JDBC驱动在默认情况下会无视executeBatch()语句,把我们期望批量执行的一组sql语句拆散,一条一条地发给MySQL数据库,批量插入实际上是单条插入,直接造成较低的性能。
executeBatch():是一个 JDBC 方法,用于批量执行 SQL 语句。该方法可以一次性执行多个 SQL 语句,从而提高数据库操作的效率
只有把rewriteBatchedStatements参数置为true, 驱动才会帮你批量执行SQL,另外这个选项对INSERT、UPDATE、DELETE都有效
三、怎么用?
将该参数添加到mysql的链接url
##配置链接mysql的时候将参数添加上并且将参数设置成true
spring:
datasource:
url: jdbc:mysql://localhost:3306/learn_a?rewriteBatchedStatements=true&useSSL=false&serverTimezone=UTC&
username: *******
password: *******
driver-class-name: com.mysql.cj.jdbc.Driver
四、影响
根据官网文档的示意,本地测试时没有发现update和delete的实际优化(各位看官老板发现可以私聊博主)
4.1 INSERT
我们对INSERT进行多场景分析,部分数据数据一致场景、部分数据一致场景、数据完全不一致场景三种场景进行分析
4.1.1 场景一(数据一致)
SQL
--优化前
INSERT INTO users ( id, username, password, email ) VALUES ( 0, '张老0', '02103', '02103' )
INSERT INTO users ( id, username, password, email ) VALUES ( 0, '张老1', '12113', '12113' )
INSERT INTO users ( id, username, password, email ) VALUES ( 0, '张老2', '22123', '22123' )
--优化后
INSERT INTO users ( id, username, PASSWORD, email ) VALUES ( 0, '张老0', '02103', '02103' ),( 0, '张老1', '12113', '12113' ),( 0, '张老2', '22123', '22123' )
mysql日志输出
4.1.2 场景二(数据部分不一致)
场景2.1(1,2一致,3不一致)
SQL
--优化前
INSERT INTO users ( id, username, email ) VALUES ( 0, '张老0', '02103' )
INSERT INTO users ( id, username, email ) VALUES ( 0, '张老1', '12113' )
INSERT INTO users ( id, username, password, email ) VALUES ( 0, '张老2', '22123', '22123' )
--优化后(可以看到只有相邻的会进行合并优化)
INSERT INTO users (id, username, email) VALUES (0, '张老0', '02103'), (0, '张老1', '12113');
INSERT INTO users ( id, username, password, email ) VALUES ( 0, '张老2', '22123', '22123' )
mysql日志输出
场景2.2(1,3一致 2不一致)
SQL
--优化前
INSERT INTO users ( id, username, email ) VALUES ( 0, '张老0', '02103' )
INSERT INTO users ( id, username, password, email ) VALUES ( 0, '张老1', '12113', '12113' )
INSERT INTO users ( id, username, email ) VALUES ( 0, '张老2', '22123' )
--优化后(我们可以看到优化是和顺序是有关联的,所以这种极端的场景效率不会提升)
INSERT INTO users ( id, username, email ) VALUES ( 0, '张老0', '02103' )
INSERT INTO users ( id, username, password, email ) VALUES ( 0, '张老1', '12113', '12113' )
INSERT INTO users ( id, username, email ) VALUES ( 0, '张老2', '22123' )
mysql日志输出
4.1.3 场景三(数据全不一致)
SQL
--优化前
INSERT INTO users ( id, username ) VALUES ( 0, '张老0' )
INSERT INTO users ( id, username, password ) VALUES ( 0, '张老1', '12113' )
INSERT INTO users ( id, username, email ) VALUES ( 0, '张老2', '22123' )
--优化后
INSERT INTO users ( id, username ) VALUES ( 0, '张老0' )
INSERT INTO users ( id, username, password ) VALUES ( 0, '张老1', '12113' )
INSERT INTO users ( id, username, email ) VALUES ( 0, '张老2', '22123' )
mysql日志输出
五、注意事项
-
数据库:表的设计必须存在默认值或者可以为NULL
-
使用saveBatch()批量插入会将sql整合为一条,需要注意合并后数据量过大引发的报错,具体大小可以查询数据库的max_allowed_packet
报错:Packet for query is too large (5,509,325 > 4,194,304). You can change this value on the server by setting the 'max_allowed_packet' variable.
查询max_allowed_packet命令:SELECT CONCAT( ROUND( (@@max_allowed_packet / (1024 * 1024)) ), ' MB' ) AS max_allowed_packet_mb;
规避方式:
调整max_allowed_packet的大小
写方法的时候根据插入数据量自己写个使用saveBatch(Collection<T> entityList, int batchSize)
六、结论
-
数据库:对数据表创建有要求,字段设置可以为空或存在默认值。
-
驱动:对mysql驱动版本存在要求,要求5.1.13以上版本(测试5.1.12也是可以的)。
-
数据:当存储的无规则数据格式,无法进行优化效率很低。
-
根据上述验证过程sql优化存在顺序性,只有相邻的两条数据格式一致才会优化,并不会跨行优化。
-
经测试两条以上就会合并,网上部分文章说小于三条并不会优化存在出入。
想了解更多的请关注博主另一篇文章:MyBatis 批量插入-优化&效率对比