幼儿饰品瑜伽美体用品微软
投稿投诉
微软创意
爱情通信
用品婚姻
爱好看病
美体软件
影音星座
瑜伽周边
星座办公
饰品塑形
搞笑减肥
幼儿两性
智家潮品

调优MyBatissaveBatch25倍性能

  最近在压测一批接口,发现接口处理速度慢的有点超出预期,感觉很奇怪,后面定位发现是数据库批量保存这块很慢。
  这个项目用的是mybatisplus,批量保存直接用的是mybatisplus提供的saveBatch。
  我点进去看了下源码,感觉有点不太对劲:
  我继续追踪了下,从这个代码来看,确实是for循环一条一条执行了sqlSession。insert,下面的consumer执行的就是上面的sqlSession。insert:
  然后累计一定数量后,一批flush。
  从这点来看,这个saveBach的性能肯定比直接一条一条insert快。
  我直接进行一个粗略的实验,简单创建了一张表来对比一波!粗略的实验
  1000条数据,一条一条插入TestvoidMybatisPlusSaveOne(){SqlSessionsqlSessionsqlSessionFactory。openSession();try{StopWatchstopWatchnewStopWatch();stopWatch。start(mybatisplussaveone);for(inti0;i1000;i){OpenTestopenTestnewOpenTest();openTest。setA(ai);openTest。setB(bi);openTest。setC(ci);openTest。setD(di);openTest。setE(ei);openTest。setF(fi);openTest。setG(gi);openTest。setH(hi);openTest。setI(ii);openTest。setJ(ji);openTest。setK(ki);一条一条插入openTestService。save(openTest);}sqlSession。commit();stopWatch。stop();log。info(mybatisplussaveone:stopWatch。getTotalTimeMillis());}finally{sqlSession。close();}}
  可以看到,执行一批1000条数的批量保存,耗费的时间是121011毫秒。
  1000条数据用mybatisplus自带的saveBatch插入TestvoidMybatisPlusSaveBatch(){SqlSessionsqlSessionsqlSessionFactory。openSession();try{ListOpenTestopenTestListnewArrayList();for(inti0;i1000;i){OpenTestopenTestnewOpenTest();openTest。setA(ai);openTest。setB(bi);openTest。setC(ci);openTest。setD(di);openTest。setE(ei);openTest。setF(fi);openTest。setG(gi);openTest。setH(hi);openTest。setI(ii);openTest。setJ(ji);openTest。setK(ki);openTestList。add(openTest);}StopWatchstopWatchnewStopWatch();stopWatch。start(mybatisplussavebatch);批量插入openTestService。saveBatch(openTestList);sqlSession。commit();stopWatch。stop();log。info(mybatisplussavebatch:stopWatch。getTotalTimeMillis());}finally{sqlSession。close();}}
  耗费的时间是59927毫秒,比一条一条插入快了一倍,从这点来看,效率还是可以的。
  然后常见的还有一种利用拼接sql方式来实现批量插入,我们也来对比试试看性能如何。
  1000条数据用手动拼接sql方式插入
  搞个手动拼接:
  来跑跑下性能如何:TestvoidMapperSaveBatch(){SqlSessionsqlSessionsqlSessionFactory。openSession();try{ListOpenTestopenTestListnewArrayList();for(inti0;i1000;i){OpenTestopenTestnewOpenTest();openTest。setA(ai);openTest。setB(bi);openTest。setC(ci);openTest。setD(di);openTest。setE(ei);openTest。setF(fi);openTest。setG(gi);openTest。setH(hi);openTest。setI(ii);openTest。setJ(ji);openTest。setK(ki);openTestList。add(openTest);}StopWatchstopWatchnewStopWatch();stopWatch。start(mappersavebatch);手动拼接批量插入openTestMapper。saveBatch(openTestList);sqlSession。commit();stopWatch。stop();log。info(mappersavebatch:stopWatch。getTotalTimeMillis());}finally{sqlSession。close();}}
  耗时只有2275毫秒,性能比mybatisplus自带的saveBatch好了26倍!
  这时,我又突然回想起以前直接用JDBC批量保存的接口,那都到这份上了,顺带也跑跑看!
  1000条数据用JDBCexecuteBatch插入TestvoidJDBCSaveBatch()throwsSQLException{SqlSessionsqlSessionsqlSessionFactory。openSession();ConnectionconnectionsqlSession。getConnection();connection。setAutoCommit(false);Stringsqlinsertintoopentest(a,b,c,d,e,f,g,h,i,j,k)values(?,?,?,?,?,?,?,?,?,?,?);PreparedStatementstatementconnection。prepareStatement(sql);try{for(inti0;i1000;i){statement。setString(1,ai);statement。setString(2,bi);statement。setString(3,ci);statement。setString(4,di);statement。setString(5,ei);statement。setString(6,fi);statement。setString(7,gi);statement。setString(8,hi);statement。setString(9,ii);statement。setString(10,ji);statement。setString(11,ki);statement。addBatch();}StopWatchstopWatchnewStopWatch();stopWatch。start(JDBCsavebatch);statement。executeBatch();connection。commit();stopWatch。stop();log。info(JDBCsavebatch:stopWatch。getTotalTimeMillis());}finally{statement。close();sqlSession。close();}}
  耗时是55663毫秒,所以JDBCexecuteBatch的性能跟mybatisplus的saveBatch一样(底层一样)。
  综上所述,拼接sql的方式实现批量保存效率最佳。
  但是我又不太甘心,总感觉应该有什么别的法子,然后我就继续跟着mybatisplus的源码debug了一下,跟到了mysql的驱动,突然发现有个if里面的条件有点显眼:
  就是这个叫rewriteBatchedStatements的玩意,从名字来看是要重写批操作的Statement,前面batchHasPlainStatements已经是false,取反肯定是true,所以只要这参数是true就会进行一波操作。
  我看了下默认是false。
  同时我也上网查了下rewriteBatchedStatements参数,好家伙,好像有用!
  我直接将jdbcurl加上了这个参数:
  然后继续跑了下mybatisplus自带的saveBatch,果然性能大大提高,跟拼接SQL差不多!
  顺带我也跑了下JDBC的executeBatch,果然也提高了。
  然后我继续debug,来探探rewriteBatchedStatements究竟是怎么rewrite的!
  如果这个参数是true,则会执行下面的方法且直接返回:
  看下executeBatchedInserts究竟干了什么:
  看到上面我圈出来的代码没,好像已经有点感觉了,继续往下debug。
  果然!sql语句被rewrite了:
  对插入而言,所谓的rewrite其实就是将一批插入拼接成insertintoxxxvalues(a),(b),(c)。。。这样一条语句的形式然后执行,这样一来跟拼接sql的效果是一样的。
  那为什么默认不给这个参数设置为true呢?
  我简单问了下ChatGPT:如果批量语句中的某些语句失败,则默认重写会导致所有语句都失败。批量语句的某些语句参数不一样,则默认重写会使得查询缓存未命中。
  看起来影响不大,所以我给我的项目设置上了这个参数!最后
  稍微总结下我粗略的对比(虽然粗略,但实验结果符合原理层面的理解),如果你想更准确地实验,可以使用JMH,并且测试更多组数(如5000,10000等)的情况。
  批量保存方式
  数据量(条)
  耗时(ms)
  单条循环插入
  1000hr121011hrmybatisplussaveBatch
  1000hr59927hrmybatisplussaveBatch(添加rewtire参数)
  1000hr2589hr手动拼接sql
  1000hr2275hrjdbcexecuteBatch
  1000hr55663hrjdbcexecuteBatch(添加rewtire参数)
  1000hr324hr所以如果有使用jdbc的Batch性能方面的需求,要将rewriteBatchedStatements设置为true,这样能提高很多性能。
  然后如果喜欢手动拼接sql要注意一次拼接的数量,分批处理。
  链接:https:juejin。cnpost7217836890120306746

长白山天池的水只出不进,为何没有干涸?专家称水来自青藏高原?长白山天池作为三江之源,它供给着鸭绿江、松花江、图们江的水源。位于海拔2189。1米的火山口,是世界上海拔最高的火山湖。千百年来长白山天池里的水,都是只出不进的状态,但是它为什……阳溪穴有效缓解耳鸣的穴位您是否曾经因为耳朵内部总在轰隆轰隆响,或者像虫鸣鸟叫一样让您异常难受,可是您却不知道是什么原因?您是否曾经因为头痛而辗转难眠?您是否曾经因为运动过度,或者频繁使用电脑,导致手腕……就在今天,大卫罗宾逊保持了28年的纪录被打破了大卫罗宾逊是马刺的传奇巨星,他1987年以状元秀身份被马刺队选中,其NBA生涯全部效力马刺,他为马刺出战了14个赛季,一共打了987场常规赛,场均轰下21。1分10。6板2。5……幸亏这位滑雪大魔王不玩单板,否则谷爱凌将面对强敌为祖国争光的谷爱凌谷爱凌在冬奥会上以超高难度超越了所有对手,以94。5的高分,逆转局势,成功拿下女子自由滑雪大跳台的冠军,拿下了中国队的第三枚奥运金牌,可以说是一举封神!……天天游讯NS破解团队被罚千万CDPR不承认2077涉嫌欺诈NewsNS破解团队成员在被罚款千万美元:民事诉讼败诉据VGC报道,之前出售破解NS的黑客组织TeamXecuter的成员加里鲍瑟尔被处以1000万美元的罚款。……新疆广汇险胜广东男篮原因浮出水面,不是运气,也不是战术新疆广汇险胜广东男篮原因浮出水面,不是运气,也不是战术。网友热议一针见血地指出:广东输新疆的最大原因是轻视对手,整体都在梦游,主教练杜锋战术出问题,外援莱多的发挥让人无语,这个……严惩国际足联!深夜23点俄足协上诉,中国网友别跟欧美讲公平最近大家应该都知道了,就是有关国际足联,然后欧足联,他们针对着俄罗斯做的一系列得很不公平的举动,已经彻底地激怒了俄罗斯,俄罗斯在昨天正式反击,俄罗斯足协向国际体育仲裁法庭正式提……这几道家常菜易学易做,赶紧来试试吧竹笋干炒肉配料:五花肉、竹笋干、盐、酱油、植物油做法:将干竹笋浸泡在冷水中约一天。将肉切片备用,油热后,加入葱、姜、蒜炒香,放肉翻炒将肉炒至金黄,加入竹笋炒,……80的青少年活动量不足,你家娃达标了吗?孩子的健康,是家长们最挂心的问题,娃的营养能不能跟上,娃的衣服有没有穿暖,娃的饮食合不合理但是!很多家长都忽略了一个很重要的健康问题娃的身体活动量!全球80的青少年……三八祝福语怎么写简单快来看看1、妇女节到,祝美女福气多多,好运连连;富贵如云,应接不暇;扶摇直上,攀龙附凤;妇女节快乐,万事如意。2、你灿烂的笑脸,给三月带来了温暖;你甜美的微笑,给三月带来了生机;……七十岁的身子四十岁的脸!垂死挣扎有何用?一个大姐,从后面看身子,弯腰驼背,如同七十岁的大妈,从前面看脸,油光铮亮,如同四十多岁的大姐姐。赵姐今年六十出头了,老两口都有退休金,家境还算可以,孙子孙女也都上学了,不……格局大了,人生就顺了余秋雨说过:人的生命格局一大,就不会在琐事上沉沦。一个人有远大的目标,就不会在烂人烂事上纠缠。因为他明白,自己的人生还有很多事情要做,没有必要因为一些人,一些事来消耗自己……
10场比赛,场均21。9分!被湖人轻视,如今完成打脸!大合同海水不可斗量,人亦不可貌相。只看身体素质,德斯蒙德贝恩确实很难引起旁人注意。1米96的身高,搭配1米96的臂展,同时还没有令人惊叹的第一步和运动能力,打二号位持球不……金铲铲之战S6顶级暴爽阵容!塔利斯议员!一炮一窝Hello,大家好!我是兔子,今天继续为大家分享娱乐阵容,写娱乐不是初衷,但是有兄弟们想要看况且确实上分阵容写干了,再写上分阵容基本都会是重复的,肯定有兄弟会在后台开喷,……抑郁症成为七成年轻人自杀原因,毛星云也是其受害者之一抑郁症,已经成为了仅次于癌症的杀手,每年不知夺取了多少年轻人的生命。十二月十三号,随着顶级游戏开发大神毛星云跳楼的消息爆出,抑郁症又成为了刷爆各大社交平台的热门话题,为什么抑郁……卢卡库专访我愿为劳塔罗而死永远不会加盟尤文和米兰日前卢卡库接受意大利天空体育采访的部分内容引起了轩然大波,目前采访的全部内容已经被公开。相关阅读:【卢卡库:我对目前在切尔西的情况不太满意;想在巅峰期回国米】你现在……和闺蜜们的三亚之旅,坐游艇乘风破浪吃海鲜看晚霞赏繁星写在前面三亚的蓝天碧海总是动人的景致,到三亚来上一个度假总是最好的选择。在这里和阳光海风来个一个亲密的接触,懒洋洋的度假总会让精神和心脏也得到最好的放松。又一……闪亮外观美妆技术,小米civi4月21日发布,女孩子们可冲在即将到来的4月21日,小米Civi系列便会更新带来新品小米Civi1S,最近关于这款新品的宣传信息也很多,咱们不妨一起来看看了解一下。此次小米Civi1S将重点升级颜值……新版本T0射手诞生,百里守约也被打懵了,出电刀能增加70伤害百里守约是当前版本最热门的射手,不知道是不是长期处于禁用位置的原因,玩家对百里守约有一种近乎疯狂的执念,只要没人禁百里守约,那么双方的队伍中一定会有人选百里守约。如果是第一个选……碎片商店偷偷更新!皮肤阵容十分豪华,1月皮肤优化官宣前言:众所周知,抢先服已经开启了s26赛季,新赛季的更新公告也全面官宣了。此次新赛季改动涉及面还是很广的,不过主要集中在装备、远古生物、视觉效果和英雄手感优化等。其中有争……数字文旅的精彩生活工作人员在一码游贵州全域智慧旅游平台后台查看游客信息。新华社记者欧东衢摄云上剧院、数字展览、智慧景区近年来,大批数字文旅项目涌现。文旅产业与科技相遇,催生出许多新业态、新……红警2,当代中年人的避风港因为粉丝群里有一个小粉丝,天天发红警的内容,今天又忍不住选了红警的题材。至于红警与命令与征服的关系、西木工作室背后的故事啊这种老生常谈的东西今天咱就不扒了,就聊一聊自己与……欠债必须还钱?2022年新规下,这7种欠款可以不用还了?播报文章新言说财经2022062322:35四川优质财经领域创作者关注前言虽然平时人们做好了准备,应付各种突发事件,但是当意外突然来临的时候,仍然让人……17万头牲畜返回中国内蒙古夏季牧场最近,中国内蒙古自治区科尔沁旗的当地牧民正忙于将约17万头牲畜从冬季牧场转移到夏季牧场。旅程于6月15日开始,大约花了一周时间到达。当地政府在沿线设立了许多服务站,为牧民提供帮……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网