范文健康探索娱乐情感热点
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

线上sql执行慢,分享3个优化案例

  前段时间,博主线上项目的几个后端接口执行耗时达到了三、四秒钟以上,查看接口代码,发现 sql 语句执行过慢,于是开始分析 sql 执行 这里把比较经典的优化案例分享给大家。  本文所讲述 MySql 8.0+ 代码演示地址:https://github.com/wayn111/newbee-mall-pro 博主github地址:github.com/wayn111 欢迎大家关注,点个star 一、or 查询条件错误
  线上有一个第三方账户扫码绑定手机号登录的接口,这个接口正常逻辑如下:  使用 苹果、QQ、微信获取扫描客户端登录二维码,获取用户第三方账户唯一ID后。 判断第三方账户ID是否存在用户表中,存在且已绑定手机号则直接返回用户 token 进行登录操作。 不存在则提示用户进行绑定手机号操作。 用户填写手机号及短信验证码后,进行第三方账户唯一ID与手机号的绑定,成功则返回用户 token 进行登录操作。
  博主记得这个接口是在21年10月上线的,到现在经历了一年多,接口执行时间是越来越慢,初步分析是用户数量持续增长,用户表记录越来越多,导致 sql 查询执行效率越来越低导致。这里用 vc_member_bak 进行举例,表结构以及数据展示,其中  apple_id、weixn_id、qq_id  有建立索引
  vc_member_bak 表数据量在46万左右,开启日志分析后,发现是下面这条 sql 执行太慢导致  SELECT * FROM vc_member  WHERE qq_id = "xxx" OR app_id = "xxx" OR weixin_id = "xxx" ;
  执行结果:
  需要1.3秒左右,这是在我本地模拟的数据,线上用户在百万级别,耗时已经达到2、3秒,于是博主开始上 explain,分析 sql 执行
  由于 explain 结果中 key 列为空,明显可知虽然 possible_keys 列有值,但是执行过程中,没有使用索引导致全表查询,从rows 列为46万可以看出已经基本接近于全表查询。
  那么问题出在哪里?我们不是已经给  apple_id、weixn_id、qq_id  三个字段都添加索引了吗。
  于是博主仔细查询 sql 语句发现里面有坑,查询的 where 条件上使用的三个条件字段是分别是  app_id、weixin_id、qq_id ,而我们的索引字段是 apple_id、weixn_id、qq_id ,很明显这是查询字段 apple_id 写成 app_id 了导致。app_id 没有加索引,所以在 or 条件查询下执行的就是全表扫描。
  更改字段后执行结果:
  Ok,这里发现了是查询字段写错了,那么修改查询字段正确后,查询0.18秒就正常了。  二、update 批量更新优化
  博主以前线上项目( Spring Boot + Mybatis )有一个接口需要批量更新库存,当时博主本着不能再代码 for 循环中执行更新逻辑的初衷,决定再 xml 文件中使用 foreach 标签执行批量更新逻辑,展示如下:               update tb_newbee_mall_goods_info          set stock_num = stock_num-#{stockNumDTO.goodsCount}         where goods_id = #{stockNumDTO.goodsId}          and stock_num>=#{stockNumDTO.goodsCount}          and goods_sell_status = 0;      
  可以看出这个更新 sql 本质上就是在一条 sql 里执行了多个 update 语句。这个写法虽然不是在代码 for 循环中执行,但是这条 sql 语句执行时,MySql 任然是单条单条执行的。这里用 tb_newbee_mall_goods_info 表举例,表结构展示:
  3个 update 语句同时执行结果如下:
  如上,假如其中一个 update 语句需要耗时40毫秒,那么当有100条 update 语句时,接口耗时就会来到4秒,这显然是不可接受的。
  那有没有一种高级一点的写法来执行 update 批量更新嘞?
  当然是有的,博主后来使用了  update + case  语句完成这个批量更新功能,
  update + case sql 如下: UPDATE tb_newbee_mall_goods_info  SET stock_num = CASE 		goods_id  		WHEN 10003 THEN 		stock_num - 1  		WHEN 10004 THEN 		stock_num - 1  		WHEN 10005 THEN 		stock_num - 1  		ELSE stock_num  END  WHERE 	goods_id IN ( 		10003, 		10004, 	10005  	)
  我们通过  SET stock_num = case goods_id when 10004 then stock_num - 1 ... ELSE stock_num END  条件,可以将对应 goods_id 的记录的库存数量设置成我们想要的结果。
  PS:需要注意的就是  case when then 语句不匹配时会返回 null,那就会造成不匹配的库存更新为 null。所以 ELSE stock_num END 条件一定要带上,当不匹配 case when then 条件时,将库存数量设置成原本数量。where 条件在这里其实可以不加,它起到的作用是限制更新范围,但是建议还是要加上,避免 sql 写错时,造成脏数据范围过大。
  update + case 执行结果:
  可以看出我们更新了3条记录,耗时50毫秒,更新记录越多时,优化效果也就明显。  三、多线程优化大批量数据插入速度
  博主线上有一个 cdk 兑换码业务,运营在后台创建一批 cdk 码时,系统会将这批码插入数据库中保存,这样可以保证用户兑换 cdk 时,码在数据库存在才能兑换,保障安全性。当运营创建十万条cdk记录时,线上耗时达到了十几秒。这里用 cdk_info 表举例,表结构展示:
  假如我们现在需要保存十万条 cdk_info 记录,分批次保存代码如下:  /**  * cdk创建  */ @Test public void cdkCreate() {     Integer num = 100000;     List list = new ArrayList<>(num);     Date date = new Date();     String createUser = "test";     for (Integer i = 0; i < num; i++) {         CdkInfo temp = new CdkInfo();         temp.setCdkNo(String.valueOf(i));         temp.setCreateTime(date);         temp.setCreateUser(createUser);         list.add(temp);     }     long begin = System.currentTimeMillis();     boolean flag = false;     for (List cdkInfos : ListUtil.partition(list, 1000)) {         flag = cdkInfoService.saveBatch(cdkInfos, cdkInfos.size());         if (!flag) {             break;         }     }     long end = System.currentTimeMillis();     log.info("执行耗时:" + (end - begin) + "ms");     Assert.isTrue(flag, "批量更新失败"); }
  执行耗时:
  可以看到在单一线程下,插入十万条记录差不多需要15秒了,这十万条数据之间没有关联,互不影响,那我们可以通过线程池提交单一批次的保存任务,配合  CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join()  方法,等所有任务执行完成拿到结果。代码如下: /**  * 通过线程池创建cdk  */ @Test public void asyncCdkCreate() {     int num = 100000;     List list = new ArrayList<>(num);     Date date = new Date();     String createUser = "test";     for (Integer i = 0; i < num; i++) {         CdkInfo temp = new CdkInfo();         temp.setCdkNo(String.valueOf(i));         temp.setCreateTime(date);         temp.setCreateUser(createUser);         list.add(temp);     }     long begin = System.currentTimeMillis();     List flagList = new ArrayList<>();     List> futures = new ArrayList<>();     for (List cdkInfos : ListUtil.partition(list, 1000)) {         CompletableFuture future = CompletableFuture.runAsync(() -> {             boolean b = cdkInfoService.saveBatch(cdkInfos, cdkInfos.size());             flagList.add(b);         }, ForkJoinPool.commonPool());         futures.add(future);     }     CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();     long end = System.currentTimeMillis();     log.info("执行耗时:" + (end - begin) + "ms");     Assert.isTrue(flagList.stream().filter(aBoolean -> !aBoolean).findFirst().orElse(true), "批量更新失败"); }
  执行耗时:
  可以看到执行耗时2.5秒,执行时间缩短了6倍。  总结
  到这里,本文所分享的3个优化案例就介绍完了,希望对大家日常开发有所帮助,喜欢的朋友们可以点赞加关注。

PCL夏季赛W2D14AM57分第二韦神爆发砍13杀!CTG三鸡登顶2022年8月2日,PCL夏季赛第二周周中赛第一日,由米拉玛赛区和艾伦格赛区出战,CTG延续周中赛的统治力,6场3鸡狂揽74分统治比赛。4AM也在韦神的带领下打出精彩表现,拿到57梦幻西游175级全能无底洞,不磨特技全都有,平民看了都眼馋Hello大家好,我是浩仔!关注浩仔,每天给你带来最新梦幻西游游戏资讯!浩仔给大家展示的最多的应属175级的角色,这个等级是目前梦幻西游的最高等级,有谛听的加持,PK比其他等级看的影之诗关于我使用速死在无限大赛豪取一胜的那些事作者NGAAlbert47刚刚在隔壁看无限战报,突然看到了一套速死,当时就觉得文艺复兴啊,立马扔下国际服的田所罗门法,来国服打大赛了。首先是使用了一些inm之力,roll了4把先手512GB麒麟芯片,二手华为高端仅2608元,比官方商城便宜近2400元相信很多朋友在华为官方商城里面也看到了开设的华为认证二手机,没错华为商城已经开始售卖二手机了,这个在以往是不存在的,小米OPPO和vivo的官方商城一般不会出售二手机,其实二手机的曝iPhone14全球首发黑科技亮相,前辈机皇沦为弃机百元抢购iPhone13Pro是目前最均衡的iPhone。性能方面,搭载了满血版苹果A15处理器,6核CPU和5核GPU,流畅的iOS操作系统,足以保证机器5年不卡顿。苹果A15依然是目前两款王炸产品,城市合伙人计划萤石召开2022智能锁新品发布会作为一家创新型公司,萤石过去几年营收呈快速增长格局,由2018年15。2亿元营收,到2020年增长到30。8亿元,保持着高速的年复合增长。在布局全屋智能后,萤石以安全为核心,逐步形上市4个月跌到3209元,IP6866W5倍光学,鸿蒙手机试图挽回销量伴随着华为被迫让出了智能手机市场份额,给了国产手机很多机会,然而华为并没有就此放弃智能手机业务,仍旧选择推出新机型,只不过新机发布时间被延迟了,并且在配置上存在诸多被诟病的地方,如Netflix版生化危机没那味?如同粗制滥造的小成本电影Capcom旗下生化危机系列至今已经多次被改编成真人或CG影视作品,在游戏领域之外也大受欢迎。2022年7月14日,由Netflix制作推出的真人剧集生化危机正式上线。作为一名看完学医如何拯救世界?守望先锋归来原始暴怒禅雅塔拒绝华丽呼哨控制链,打得准才是硬道理!守望先锋归来本轮B测,谈起来最大的改动是6V6模式变成5V5模式,其实还有一点就是治疗和C位的控制几乎全部变成软控。旧版本源氏拔刀切入后,领一英雄联盟电竞经理现版本最强势的4套主流阵容,0氪土豪都能玩本篇攻略将为大家介绍现版本最强力的4套阵容。无论你是究极氪佬,还是小资轻氪,亦或是终极白嫖党,都能从中找到适合自己的一套体系这四套阵容分别是EDG,RNG,TES,Theshy散搭攻略心得原神海岛主线任务终完结草神竟在最后登场今天海岛开放了亘古的苍星(莫娜主题秘境)和如诗如歌夏之梦(草神彩蛋)两部分。让海岛开放更多区域的同时也说明海岛的故事暂时告一段落。本文将会聚焦于这两个海岛主线任务及相关宝箱的解析,
中超4消息!中超积分榜更新,三镇爆冷或丢冠,泰山紧咬不放第1个消息来自于中超积分榜。中超第17轮补赛,几场比赛的比分确实有些让人意外。武汉三镇在一场进球大战中34不敌沧州雄狮,而山东泰山则是以40大胜深圳队,北京国安与大连人战成22平,欧国联最新积分战报葡萄牙末轮只需战平西班牙瑞士2连胜升至第3北京时间9月25日凌晨,202223赛季欧国联A级小组赛第5轮进行了最后2场比赛的争夺,今天进行的是C组两场较量。经过一番鏖战,西班牙主场12不敌瑞士,葡萄牙客场40捷克。上轮葡萄什么是素圈戒指?佩戴素圈戒指都有什么讲究?问题怎么才能每天都收到这种文章呢?答案只需要点击右上角关注即可。大家好,我是东方,今天咱们来聊一聊这几年,人们在配饰方面的选择更倾向于简约时尚,不追求繁重的工艺设计和花里胡哨的装饰18岁红遍全球,40岁美得睿智优雅,她的人生太传奇话说,上周周报里,我们提到了大嘴安看秀,美到发光。她去看的,正是MichaelKorsCollection2023年春夏大秀。小郑特意去网上看了整个视频,都是给摩登都市女郎设计的衣正式退役!新疆男篮名将无球可打,投奔名帅被拒绝,告别CBA赛场这个夏天,CBA上演了一次失业潮,众多名将都因为没有找到新工作而告别了赛场,其中就包括了新疆名将买尔丹。过去两个赛季他在深圳男篮效力,通过减重,他给人焕然一新的感觉,不过买尔丹还是央视NBA解说历史最早是每周日下午两点在CCTV2会有NBA比赛的录像重播,解说是韩乔生孙正平,评论员是徐济成苏群张卫平。早期央视主持人堪称全才,韩乔生孙正平都不是只专注在某一项比赛里,而是各项比赛热身赛0完胜加纳北京时间9月24日凌晨2点30分,一场国际足球热身赛在巴西队和加纳队之间进行。上半场,马尔基尼奥斯头球破门,随后内马尔两次送出助攻,理查利森梅开二度下半场,两队都没有再进球。最终,20!亚洲第2太强了,击败世界第13,改写29年历史,中国队没比赛麒麟杯开打,日本男足和美国男足过招,经过全场比赛的对决,日本队以20的比分战胜了对手,29年来,日本队首次击败世界第13,为世界杯做好准备。当我们的近邻取胜世界强队的时候,我们的国79分钟绝杀,10爆冷!亚洲第一掀翻乌拉圭,国足差距太大世界杯的脚步临近,各支参赛队都抓紧时间进行热身。9月24日凌晨,伊朗和乌拉圭进行一场友谊赛。全场比赛,伊朗都被对手压着踢,但凭借塔雷米的进球,10击败乌拉圭。根据最新一期国际足联排羽坛名宿葛菲父亲早逝亲情有泪,退役结婚后人生现状怎样?头条创作挑战赛点击关注,每天都有名人故事感动您!葛菲近照葛菲是公认的羽毛球双打奇才,运动生涯她共夺得13次世界冠军,还夺得7次亚洲冠军,11次全国冠军,创造了世界羽坛的奇迹。199李梦王思雨表现出色,中国女篮负美国队,虽败犹荣女篮世界杯焦点之战,中国队迎战美国队。经过几轮比赛之后,小组排名中中国队两战全胜,以净胜分高于美国成功排在小组第一的位置,同样两战全胜的美国队排在第二位。今天的这场比赛,则是小组第