mysql慢sql优化实战:in order by优化处理

news/2024/10/17 12:29:11/

背景

     线上查询慢的问题日益突出,专门写一个帖子记录一下处理过程,会定期更新优化处理方案
     套餐余量统计查询菜单,数据库查询时间一分钟五十秒,优化之后耗时109毫秒,性能提升很大.所有时间统计均以数据库层面进行统计.用户使用层面因为有数据传输、带宽、业务逻辑处理等因素查询时间会更长,只看数据库查询层面可以排除其他因素影响。
     待优化sql:

SELECT manage_staff_card.id,manage_staff_card.card_no, manage_staff_card.status, manage_staff_card.rest_count,manage_staff_card.card_type, manage_card.time_type , manage_staff_card.single_priceFROM manage_staff_card LEFT JOIN `manage_staff` ON manage_staff.`login` = manage_staff_card.`login` LEFT JOIN `manage_card`ON manage_card.`id` = manage_staff_card.`card_id` LEFT JOIN `manage_studio` ON manage_studio.`id` = manage_staff_card.`studio_id`LEFT JOIN `manage_staff_studio` ON manage_staff_studio.`login` = manage_staff_card.`login` AND manage_staff_studio.`studio_id` = manage_staff_card.`studio_id`LEFT JOIN `manage_user_studio` ON manage_user_studio.`login` = manage_staff_studio.`teacher_login` AND manage_staff_studio.`studio_id` = manage_user_studio.`studio_id`LEFT JOIN `manage_contract_card` ON manage_contract_card.`staff_card_id` = manage_staff_card.`id` LEFT JOIN `manage_contract` ON manage_contract.`contract_no` = manage_contract_card.`contract_no`WHERE manage_staff_card.status IN(8,5,15,20) ORDER BY manage_staff_card.create_time DESC

    执行计划如下:
在这里插入图片描述
    根据优化经验,一般type为all、index都需要进行优化,最少保证到ref。先从下面开始看
    manage_contract中type为all,看下sql中manage_contract用作表连接,直接将contract_no字段添加索引:

ALTER  TABLE  manage_contract  ADD  INDEX  idx_card_no (contract_no);

    添加成功后查询索引:

SHOW INDEX FROM manage_contract

    重新explain:
在这里插入图片描述
    type变更为ref,预估扫描的行数变更为1.继续看往下看.
    manage_contract_card中type为all,看sql中manage_contract_card中staff_card_id、contract_no在查询中都体现,是不是两个都需要创建索引呢,答案是不需要,只需要对staff_card_id进行创建索引。自己测试过两个都添加索引最终的执行计划type会变更为index,index和all都算是全表扫描,因为添加上contract_no之后再和manage_contract联查时需要按照contract_no全部扫描一遍manage_contract_card,实际上执行上一步的时候已经根据staff_card_id将符合要求的manage_contract_card查询出来,所有这里对于manage_contract_card只添加一个staff_card_id即可。
    添加索引

ALTER  TABLE  manage_contract_card  ADD  INDEX  idx_staff_card_id (staff_card_id);

    添加成功后查询索引:

SHOW INDEX FROM manage_contract_card  

    重新explain:
在这里插入图片描述
    type变更为ref,预估扫描的行数变更为1.继续看往下看.
    manage_staff_card放到最后讲是因为这个会比较特殊。首先看排序,排序会导致索引失效,对按照创建时间排序的业务来讲,可以使用主键id进行倒序可以进行替换实现业务逻辑,另外不需要单独根据创建时间字段添加索引,直接使用主键索引。毕竟不是索引越多越好。修改sql之后重新explain:
在这里插入图片描述
    type变更为index,由于是id主键排序,所以基本上开始全表扫描.下面在看manage_staff_card中status.直接给status添加索引:

ALTER  TABLE  manage_staff_card  ADD  INDEX  idx_status (STATUS); 

    重新执行explain发现索引是不生效的,是因为in会导致索引失效,继续往下看.
在这里插入图片描述

    关于in的业务场景实际开发中还是比较多的,i查阅资料总结了一下in常用的优化方案:

1.使用JOIN替代IN查询。如果条件中的IN查询可以转换为JOIN查询,有可能会对性能有一定提升
2.IN查询中的值列表存储到临时表中,然后使用JOIN查询
3.exists能否替代
注意:对于in中全部是参数值的,使用exist代替in无效

    以上各种优化方案都试过,对于本场景中in为参数值的情况,上面都不适用,这里的处理方式是对于manage_staff_card 中的status索引进行强制执行,manage_staff_card后面添加FORCE INDEX(idx_status).重新执行explain:
在这里插入图片描述
    会发现type类型变更为range.重新执行sql后耗时:0.109秒
    最终优化后的sql:

EXPLAIN  SELECT manage_staff_card.id,manage_staff_card.card_no, manage_staff_card.status, manage_staff_card.rest_count,manage_staff_card.card_type, manage_staff.real_name ,  manage_card.time_type , manage_staff_card.single_priceFROM manage_staff_card  FORCE INDEX(idx_status)LEFT JOIN `manage_staff` ON manage_staff.`login` = manage_staff_card.`login` LEFT JOIN `manage_card`ON manage_card.`id` = manage_staff_card.`card_id` LEFT JOIN `manage_studio` ON manage_studio.`id` = manage_staff_card.`studio_id`LEFT JOIN `manage_staff_studio` ON manage_staff_studio.`login` = manage_staff_card.`login` AND manage_staff_studio.`studio_id` = manage_staff_card.`studio_id`LEFT JOIN `manage_user_studio` ON manage_user_studio.`login` = manage_staff_studio.`teacher_login` AND manage_staff_studio.`studio_id` = manage_user_studio.`studio_id`LEFT JOIN `manage_contract_card` ON manage_contract_card.`staff_card_id` = manage_staff_card.`id` LEFT JOIN `manage_contract` ON manage_contract.`contract_no` = manage_contract_card.`contract_no`WHERE manage_staff_card.status IN(8,5,15,20) ORDER BY manage_staff_card.id DESC

    总结:
    1.left join中添加索引一般是从left join后面的表中的连接字段进行添加索引,而不是只要left join表的查询条件中有的字段都添加索引.
    2.order by排序时可以使用主键排序替换字符串排序;
    3.in的常用优化处理方式,上面已补充,这里不再重复;
    以上sql优化的处理过程,如果看到这里感觉有所帮助欢迎点赞或收藏!下面是最近参与的一个匿名社交类的微信小程序,有兴趣的可以看下
在这里插入图片描述


http://www.ppmy.cn/news/239658.html

相关文章

Stable Diffusion原理说明

本文参考:深入浅出讲解Stable Diffusion原理,新手也能看明白 - 知乎 目录 1、Stable Diffusion能做什么? 2、扩散模型(Diffusion model) (1)前向扩散(Forward Diffusion&#xff…

佳能相机G7 Mark Ⅱ (曝光补偿)

曝光指示表(判断正常) M模式下 曝光补偿表 P / TV / AV 何时用曝光补偿 口诀 白加(逆光人脸) 黑减(剪影5) 一般来说-1的曝光补偿已经非常能够左右画面的明暗了

佳能相机G7 Mark Ⅱ (曝光模式)

AUTO 全自动,什么都不需要调 P (初级学习) 相机只配对光圈,快门 自己可以调节的是:ISO , 曝光补偿 , 测光模式 TV(中级学习) 快门优先模式,自己调节一个快门值&#xf…

Jetson 相机编码

Jetson 相机编码 Jetson相机编码是即将发布的“实践”系列的相关代码。有三个存储库: 1. camera-caps JetsonHacks Github存储库camera-caps 通过v4l2-ctl命令行工具提供了一个图形用户界面。您可能会发现,它可以方便地检查连接到Jetson上的V4L2相机的功能。这适…

MySQL(进阶篇2.0)

SQL优化 插入数据 insert 如果需要一次性往数据库表中插入多条记录,可以从以下三个方面进行优化 1、优化方案一 批量插入数据 insert into tb_test values(1, Tom),(2,Cat),(3,Jerry);2、优化方案二 手动控制事务 start transaction; insert into tb_test v…

G7相关

如题,S屏Hboot,0.93取得root从此获得自由身!我是欧版的机器,自从从手机上更新了固件后,wifi不能用.错误!找了很久都没有找到降级刷机的方法,无奈做了金卡刷了http://u.115.com/file/f6d4603775官方的rom,昨天又看到高分控又发布了http://bbs.goapk.com/thread-23734-1-1.html无…

佳能相机G7 Mark Ⅱ (曝光三要素)

曝光三要素 光圈 可以在 AV / M 调节; 光圈可以起到控制进光量的作用; 最大的作用是可以实现背景虚化 ; 光圈越大,虚化越好 ;(也就是f值越小,光圈越大,虚化越好)&…

高频面试八股文用法篇(五) 重载和重写的区别

目录 什么是重载(Overload)和重写(Override)? 重载 重写 区别与联系 区别 联系 什么是重载(Overload)和重写(Override)? 重载 重载(overloading) 是在…