jdbc-batching
批量处理
批量插入
1 | /** |
打开mysql的general log:
1 | mysql> show variables like '%general%'; |
这里已经是开启的状态,如果没有开启可以设置下:
1 | mysql> set global general_log=1; |
上述java代码执行的时候,查看general log:
1 | 2020-05-02T23:41:28.438048Z 154 Query insert into words (`word`) VALUES('123') |
对应的抓包:
看起来是一个一个发送的,server端也是一个一个执行的。这样并不能提高效率
rewriteBatchedStatements=true
jdbc的连接上配置这个参数,重复上面的过程,得到的结果:
1 | stopwatch = 1320 |
sql被改写成了:
1 | 2020-05-03T05:27:17.921856Z 163 Connect root@localhost on test using TCP/IP |
抓包也只看到了一次请求,这个性能提升有60+倍。
批量删除
测试下批量删除会变成什么样子
1 |
|
sql是一起发过去的, response貌似是逐个返回的,看下general log:
1 | 2020-05-03T06:14:33.457011Z 180 Query delete from words where id = 99980; |
执行是一条一条执行的
内存占用过大
如果一直addBatch
,内存压力会比较大,可以分批执行下。
mysql的实现
在低版本的mysql connector里,有的不会改写成insert into xx () values
的形式,感觉是个bug;升级版本之后就可以了。
mysql-connector-java-8.0.16.jar
1 | // com.mysql.cj.jdbc.ClientPreparedStatement#executeBatchInternal |
添加事务
之前执行都是自动提交的,相当于是多个事务,这次修改成一个单独的事务看看效果:
1 |
|
General log:
1 | 2020-05-03T06:58:19.567073Z 191 Query insert into words (word) values('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123'),('123') |
执行时间:
1 | stopwatch = 2236 |
时间并没有提升,反倒有些下降,这个涉及的原因可能跟数据库的事务相关的各种配置有关系,后面再继续研究。
结论
- executeBatch要和
rewriteBatchedStatements
或allowMultiQueries
一起使用才有效果 - executeBatch执行的sql太多时最好分批次,避免对jvm造成太大的压力
- executeBatch执行的sql个数大于4