sql 批量修改_记 mybatisplus 批量插入saveBacth入坑记

背景:
  • 每天定时从sftp上下载文件,解析文件组装参数然后批量入库,方便数据组抽数。

sftp上共五个文件其中有两个文件内容可能超过几百万而数据库是mysql所以决定分表。
  • 按天分表结果就是表太多而且又浪费空间嫌疑所以pass。
  • 按月分表程序运行一年后会导致单表数据过多所以也不符合pass。
  • 按年月分表是比较符合业务需求并且不会太浪费空间所以决定按年月分表。
技术选择:
  • 技术:sharding-jdbc、mybatis-plus
  • 数据库:mysql
  • 开发工具:idea
  • 调优工具:JProfiler
因为我们要批量插入所以用mybatis-plus自带的saveBatch方法。那为啥批量插入不用单条insert呢?
是因为一个批次插入只需要一次提交从而减少了io、网络消耗。而单条插入则相当于多次提交也就是说增加了更多的io、网络消耗。
入坑:
首先:自测放款文件。
代码如下:

fcfac47de3657b73ea9d126198a50f0a.png

每批次插入时间如下:

c8c0e40ae5df2fbfcdb0d2b727bb8aee.png

由日志可见每批次插入数据库时间为300-400毫秒之间(一个批次是1000条)一秒钟大概就是3000左右
其中在组织参数时候需要查询数据库理论来讲还可以接受。
逾期文件(大概370万的数据)
代码如下:

a42c659861f1264ed5a300b842cb895a.png

每批次插入时间如下:

9abc4f27cf44dd2060cf47fa2011577f.png

两次文件落库时间对比图如下:

22494534017453801c013c8ea1b40d2e.png

通过对比发现逾期每批次落库时间竟然是放款的十几倍而且落库时间竟然高达5,6秒但是代码几乎一致为啥这个插入这么慢呢!是可忍孰不可忍,于是借助工具JProfiler进行调优看下运行时候到底哪里占用了时间。
(和idea集成请看博客link)
于是我又运行了下如图所示

6ec553ebdebc228cbef8b47e473e0757.png

有图可见我在组织参数时候用了cn.hutool.core.date.DateUtil.parse这个方法而这个方法竟然占用了20%的时间于是我将他改成了简单时间转换SimpleDateFormate。
修改后运行如下图:
成果如下和上一次对比

a60e324d495991e3dc0b5056c711beae.png

替换之后入库时间少了但是仍然在3-4秒之间仍然不能接受但是信心大增。
于是我再次运行使用神器JProfiler如下图:

71d3f9d9b35dd6696e9601195945f235.png发现在组织参数时候竟然消耗了8%难道是字段过多反射消耗的性能。                          

如下操作: 
  • 暂时删除点字段和放款表字段数量保持一致
  • 修改表的引擎由InnoDB改成(存储引擎)MYISAM
每批次插入时间如下图:

9ac30c35c3d18b983961f219249d78c7.png

发现时间只是减少了一点点结果仍然是不可以接受。
此时灵光一现又做了如下操作:
放款文件与逾期文件插入时对sql进行对比
配置文件填上log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
放款文件sql执行如下图:

2bada0f8125616997e14d69df304ccb0.png

因内容较长原谅我不能完全贴出来发现他是一次性提交插入。
逾期文件sql执行如下图:

175cba990d43a4bbe1d464d91542c392.png

虽然代码几乎一样,但是插入时候完全不一样。逾期文件插入时竟然不是按每批次1000条插入的。究竟是哪里出的问题呢?
再次执行查看表每次递增数量:

92488ae76105d9d2aa529f8ad1560120.png

发现他的确不是按每批次1000条插入。那是不是版本问题呢。于是升级了版本由3.2---->3.4
然并软:仍然不是按每批次1000条插入为什么呢?
深吸一口气,准备放大招debug,在debug的时候发现

71c6a9cba873af17847129207a583c3e.png

图片标红的地方会对比两个sql是否一致如果不一致则走进else将Statement加入到集合中最后插入时候源码如下

9e0f98e4fc6a257e9d48f170d103bbbb.png

那么逾期文件落库的时候是否sql不一致呢于是我重新运行如下

175cba990d43a4bbe1d464d91542c392.png

发现这两个inser语句是不一样的经查看文件发现有的列在解析时候是无值的。也就是说我们插入的sql秩序保持一致那么问题是否迎刃而解呢!
解决办法:
在可能为空的列上添加
@TableField(insertStrategy=FieldStrategy.IGNORED,
fill = FieldFill.DEFAULT)
再次运行如下图:

0dbd82d2f31584fc5af3146d5a1d9a3c.png

到此优化结束符合我们的预期。
结论:
虽然我每次传入了1000条但是sql不一致将不同的Statement加入集合插入的时候则遍历这个集合从而导致insert多次。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值