MySQL group by 使用临时表导致慢查询问题定位

问题描述:拼团系统突然出现很多慢查询,(拼团规则表,Frule_id是主键,Fcreate_time不是索引,Fend_time是索引字段)

语句

select * from t_group_rule group by Frule_id order by Fcreate_time desc limit 0,10;

手动执行发现需要5s钟,可是全表只有70万行数据,即使全表扫描也要不了这么久啊,果断explain一把:

Extra显示用到了临时表和排序,可是group by后面是索引啊,为什么还要用到临时表,原因是group by 后又按照其他字段做了排序,因此需要将聚合结果放在临时表中,然后再根据Fcreate_time排序。 

 

引申一下其他场景:

场景一:

select * from t_group_rule group by Frule_id order by Fend_time desc limit 0,10;

结果也一样的,因为Frule_id的排序和Fend_time的排序不一致,即group by执行完后是按照Frule_id有序,不是按照Fcreate_time有序的,因此必须将group by执行后的结果放到临时表中,再根据Fcreate_time排序。

 

场景二:

如果Frule_id和Fend_time是联合索引,那么肯定就不会用到临时表和排序。

 

场景三:

如果是order by NULL不做排序,或者按照Frule_id本身做排序,那肯定都不会用到临时表和排序:

 

结论:耗时主要用在了临时表上,而且临时表中数据比较大,达到70多万行。

优化方法:

(1)我们业务中Frule_id是递增的,因此按照Frule_id做降序即可。优化后语句:select * from t_group_rule group by Frule_id order by Frule_id desc limit 0,10; 耗时从5s降到0..01秒。

(2)如果必须按照非索引字段排序,可以利用where条件缩小查询范围,比如select * from t_group_rule where Fend_time > time1 and Fend_time < time2 group by Frule_id order by Frule_id desc limit 0,10; 这样临时表的数据就变少了,也能够减少耗时;

(3)使用联合索引,如果是group by Frule_id order by Fcreate_time,就将Frule_id和Fcreate_time建立联合索引。

第3种方法是从技术上解决问题,但是会比较受限,关键还是要根据我们自身业务,从业务优化去解决问题。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值