Mysql优化笔记
记一次由group by子句引起的性能问题
问题背景:公司系统中存在一个功能,每次查询耗时接近两到三分钟,用户体验极差。经过分析发现,该查询涉及跨库、union all、多子表等问题,关联表大约7到8张左右,跨3个库。
解决方案:
1)、首先拿到sql语句先观察语句成分和业务逻辑相关性,个人认为在mysql中使用dblink对查询效率是存在比较大的影响的,因此第一步是要减少跨库次数。比较简单的 方法就是分析业务逻辑修改sql,取消不必要的跨库步骤,这里是采用了其他库查询一次拿到结果与原sql拼接的方式处理。减少跨库后,性能提升到1分半左右
2)、观察执行计划,优化索引,这一步是大部分sql优化中都需要用到的一步,最简单高效,索引优化过程中需要注意联表语句中索引的对称性,最好根据执行计划一步一步修复索引。
举个简单例子:下列sql中T表和T1表通过id关联,如果首先默认T表的id为主键索引,若T1表的targetId 为普通索引,T2表的orther_id 无索引,则索引关联失败,查询执行计划时,在extra列会提示明显的 Using join buffer(Block Nested Loop) 。出现这个提示表示索引不对称,此列将引起极大的性能损耗。
select * from DBA.Tb1 T LEFT JOIN DBB.Tb2 T1 ON T.id = T1.target_id LEFT JOIN DBB.Tb3.orther_id WHERE T.id = ***
实际排查过程中并未发现明显的joinbuffer问题,但是通过观察执行计划的type列、key列、extra列
(执行计划排查过程中主要是对这三个表进行观察)发现存在部分关联表的extra列提示
using filesort、using temporary 这两列对查询操作都存在一定影响,using filesort影响查询效率,using temporary 增加内存消耗。看到这using filesort 首先排查是否存在排序操作,通常这个情况由order by 或者 group by 引起,检查语句中确实存在group by情况,这个时候需要通过分析业务逻辑,确定是否需要使用group by。
3)、经过排查实际问题后,发现在这个问题中,多表关联时存在业务逻辑上的问题,即数据模型上是1对多的对象,但是在业务逻辑中只需要显示1对1的结果。因此,前人在开发过程中直接了当的使用了group by 避免出现重复数据。这里的解决方案还是仔细分析业务逻辑找到正确的对应方式,如果不可避免的要去重,这里推荐使用distinct临时处理,我尝试过使用group by 和 distinct两种方式,前者在执行计划中会同时引起 using filesort 和 using temporary。后者使用后只会引起 using temporary 即后者只会创建临时表去处理,前者创建临时表还同时进行分组排序操作,故性能损耗大。
经过以上优化后,功能在生产环境的大数据量情况下,成功从查询超时优化到单词查询2s以内。(应该还有优化的空间)。
总结:Mysql优化 首先还是得从业务出发,先要保证sql语句中不存在多余的关联,多余的字段,以及关联表的顺序不能有逻辑上的错误。其次性能优化的大头可能还是在索引这一块,要熟练使用执行计划去分析sql,根据执行计划中的异常提示制定对应的解决措施。
using filesort、using temporary 这两列的问题描述可以查看下列文章
链接: Using temporary与Using filesort
对Using join buffer(Block Nested Loop) 这个问题的详细描述可以看下列文章
https://www.cnblogs.com/wqbin/p/12127711.html