mysql 慢查询调优实战

异常现象:

报错慢查询
原sql:

select id, infoid, orderid, utel, stel, refusetime, reasoncd, reason, deleteflag, params, cityid, paidanid, cateid, baojieworkertype, `operator`, refusesource, utel_encrypt, stel_encrypt 
from t_app_refusereason 
WHERE ( cityid = 18 and refusetime >= '2024-01-22 00:00:00' and refusetime <= '2024-01-23 00:00:00' and reasoncd in ( 38 , 52 , 51 , 10 , 9 ) and deleteflag = 1 ) 
order by id asc 
LIMIT 50;

索引信息:

 KEY `idx_refusetime_reasoncd_deleteflag_cityid` (`refusetime`,`reasoncd`,`deleteflag`,`cityid`) USING BTREE

进行复现:

发现确实特别慢
在这里插入图片描述

解析sql,发现走的是主键索引
在这里插入图片描述
在上线之前校验过,是可以走索引的,可能由于最近数据量的变化,mysql的优化策略变更导致不走二级索引量
在这里插入图片描述

寻找原因:

在 MySQL 中,当执行带有 ORDER BY 子句的查询时,数据库引擎可能会选择不使用二级索引而进行全表扫描。
这是因为在包含排序的情况下,数据库引擎可能认为通过覆盖索引并不会带来额外的性能提升,而直接进行全表扫描可能更为高效。

解决办法:

办法一:指定执行索引

SELECT id, infoid, orderid, utel, stel, refusetime, reasoncd, reason, deleteflag, params, cityid, paidanid, cateid, baojieworkertype, `operator`, refusesource, utel_encrypt, stel_encrypt 
FROM t_app_refusereason 
FORCE INDEX (idx_refusetime_reasoncd_deleteflag_cityid) 
WHERE (cityid = 18 AND refusetime >= '2024-01-22 00:00:00' AND refusetime <= '2024-01-23 00:00:00' AND reasoncd IN (38, 52, 51, 10, 9) AND deleteflag = 1) 
ORDER BY id ASC 
LIMIT 50;

办法二:先按二级索引里字段排序,再按id排序

SELECT id,infoid,orderid,utel,stel,refusetime,reasoncd,reason,deleteflag,params,cityid,paidanid,cateid,baojieworkertype,`operator`,refusesource,utel_encrypt,stel_encrypt 
FROM t_app_refusereason 
WHERE ( cityid = 18 AND refusetime >= '2024-01-22 00:00:00' AND refusetime <= '2024-01-23 00:00:00' AND reasoncd IN ( 38, 52, 51, 10, 9 ) AND deleteflag = 1 ) 
ORDER BY refusetime ASC ,id ASC 
LIMIT 50;

办法三:取消排序

SELECT id,infoid,orderid,utel,stel,refusetime,reasoncd,reason,deleteflag,params,cityid,paidanid,cateid,baojieworkertype,`operator`,refusesource,utel_encrypt,stel_encrypt 
FROM t_app_refusereason 
WHERE ( cityid = 18 AND refusetime >= '2024-01-22 00:00:00' AND refusetime <= '2024-01-23 00:00:00' AND reasoncd IN ( 38, 52, 51, 10, 9 ) AND deleteflag = 1 ) 
LIMIT 50;

原sql、方案一、方案二、方案三
在这里插入图片描述

最终方案:

最终选择办法三,取消排序

复盘:

为什么之前要排序?

之前遇到一种场景,在查询es时没有排序,在返回结果的边界时会出现乱序。比如分页50条查询,数据A和B都符合筛选条件,查第一页的时候数据A返回在第50条,查第二页的时候第一条希望返回数据B,结果返回的还是数据A

因为es获取数据是在不同片区拿数据,如果不指定排序字段会出现不稳定排序现象。

但是mysql索引是稳定的,所以无特殊排序要求的时候直接拿就可以了

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值