很多现代数据库都具备实时优化功能,会自己优化SQL,搞不懂为什么要在这方面投入很大人力。。。。。但是该学习还是要学习的
一、如何定位慢SQL语句
1、通过慢查询日志查询已经执行完的SQL语句
默认慢查询日志不会开启,需要手动设置,命令为
mysql> set global slow_query_log = on;
也可以根据业务设置时间阈值以及查看慢查询日志的存储位置和文件名,自行百度
然后可以通过查询日志的方式,定位到慢SQL语句,比如使用tail命令
2、通过processlist查看正在执行的慢SQL语句
这个没什么好说的,在mysql>终端中,使用show processlist指令或者show full processlist
二、如何分析慢SQL语句
使用老朋友explain关键字explain+分析的sql语句即可,一般来说,我们需要重点关注selectType,type、rows、extra、key。
关键字 | 含义 | 常见 |
---|---|---|
selectType | 查询类型 | simple |
type | 表连接类型 | ref,index,range,all |
rows | 预计需要扫描的行数 | 是估值 |
key | 实际使用的索引 | |
extra | 附加信息 | Using index,Using temporary |
使用type一表
3、分析慢SQL语句的原因
1、大部分慢SQL语句优化都跟索引有关系,查看是不是索引设置不合理,索引失效等问题
2、一部分是sql语句本身有关系,比如深分页,in元素过多等,可以考虑优化sql语句
3、与sql语句无关,比如表数据过多
- 索引失效可以去看我之前的文章https://www.cnblogs.com/spark-cc/p/16864761.html
- 如果是limit深分页的问题,基本就是limit的行数过多了,如果还不是主键索引,就会带来多次回表操作(PS:limit语句会先扫描offset+n行,然后再丢弃掉前offset行,返回后n行数据),解决这个问题可以使用延迟关联法,我们先根据条件选择出对应行数的主键,然后与整个表相关联,然后再筛选出想要的字段。
*如果是in查询范围过多,比如 in(符合条件的id值),那么会导致筛查成本过高,那么我们可以使用分批进行,如in(符合条件的id值再进行分批比如1-200符合条件的id值)
*order by,mysql会根据max_length_for_sort_data和结果行数据长度对比,如果结果行数据长度超过max_length_for_sort_data这个值,就会走rowid排序,相反,则走全字段排序,rowid排序和全字段排序最主要的区别是rowid有回表操作,全字段没有回表操作
下图是rowid排序
下图是全字段排序
还有就是如果排序的内容过大,超过规定的参数设置,内存存不下,那么就需要磁盘临时文件排序形成临时文件,然后再合并排序,类似于shuffle阶段。
所以我们可以设置max_length_for_sort_data和内容大小参数来避免走rowid以及走临时文件排序