关于 mysql 优化 —— using filesort

        笔者,只是从一个普通大学毕业,从业4年多了,接触 mysql 3年了,之前从未考虑过性能问题,只是想着如何实现功能。
        在测试数据不多的情况下,sql 的性能问题不会被显示出来。
        而现在,虽然依旧是个小公司,但是数据上百万了;虽然量级不算太大,但是 sql 的性能问题也会凸显出来。
        没人教关于如何优化 sql 的知识,只是自己瞎搞,瞎尝试。
        每一个需要过长执行时间的 sql,每一次 sql 的尝试优化,都是一次难能可贵的经验,是它们陪着我成长。
        我将记下来,遇到的问题,以及解决方案。

MySQL 官方文档: ORDER BY Optimization

  1. 关于 using filesort
            在上方的文档,介绍了为什么会出现using filesort的情况,吃了不会英语的亏,看不懂,我就简单写下我认为的。
            当为了得到跟 order by 从句中排序顺序一致的行(row),但是索引不能满足要求,mysql 需要多进行一次计算,得到排序的方案,而这就是using filesort。这也很可能造成 mysql 语句执行效率慢的问题。
            解决这个问题,需要对排序字段加索引,这样子通过索引就可以进行排序了,一般情况下加上索引会快很多,但是也不一定,需要进行测试。
            对于多条件排序,就需要做联合索引了,在8.0之前联合索引效率有的时候很差,8.0之后效率变高,下面用一个例子进行介绍。
select
      t_unit.teacherId,
      t_user.userId
from
      sys_user t_user
      inner join dean_class_unit t_unit on t_user.userId = t_unit.teacherId
order by 
      t_unit.realStartTime desc, 
      t_unit.teacherId desc

        上面的两个表,sys_user 1W数据、dean_class_unit 200W数据,因为数据量多,效率的问题,很容易表现出来。
        对于2个排序字段都添加了索引,但是执行时间:6s,explain 之后发现了 using filesort。
        经过在网上查找,得到答案,使用联合索引可以解决

ALTER TABLE `dean_class_unit`
ADD INDEX `Index_sort_realStartTime_teacherId` (`realStartTime`, `teacherId`) USING BTREE ;

        添加联合索引之后,using filesort 消失了,执行时间变为1s。
        但是如果将排序条件升序降序修改,变为:order by t_unit.realStartTime desc, t_unit.teacherId asc,执行时间又变长了,using filesort 再次出现。
        经过查询资料发现了这些知识点:
        a. mysql8.0之前,索引只有正序索引,倒序排序是把正序索引倒过来查询
        b. mysql8.0,真正支持倒序索引,但是每一条联合索引初始化都是正序索引,这个时候均正序、均倒序,执行速度都很高。但是如果交叉排序,索引不能很好地完成需求,这种情况需要专门编写多个索引(特殊需求特殊对待,另外没进行验证多个索引是否可行)
        针对上面改动之后的order by,可以让第一个索引降序,第二个索引升序:

ALTER TABLE `dean_class_unit`
ADD INDEX `Index_sort_realStartTime_teacherId` (`realStartTime` desc, `teacherId` asc) USING BTREE ;

        问题解决了,很开心,嘿嘿。

posted @ 2020-11-15 16:26  season-qd  阅读(1192)  评论(0编辑  收藏  举报