场景
环境
Mysql
InnoDB
主键:id
唯一索引:user_id,order_no
查询索引:update_time查询最新的一条
select * from t_table where user_id = '177' order by update_time desc limit 1 Explain

关于索引
根据Explain,可以看到数据查询走了唯一索引
关于排序
- 根据Explain,可以看到Using filesort
关于filesort的出现
- 第一步:根据where条件查询出来数据
- 第二步:如果存在排序,判断排序规则是否和查询出来数据的顺序关系 - 使用了索引查询,基于相同的索引内字段排序 - 顺序相同,直接返回
 
- 使用了索引查询,基于该索引外的字段,或其他索引进行排序 - 顺序不同
 
 
- 第三步:顺序不同的情况下,执行filesort逻辑 - 借助额外的存储空间暂存查询出来的数据(内存,文件)
- 在此空间内基于排序字段进行排序 - 如果排序字段有索引,基于索引排序
- 如果无索引,全表扫描
 
- 返回排序结果
 
关于filesort的性能影响
- 结果集的大小 - 需要额外的空间和时间进行排序 - sort_buffer_size 判断使用内存还是磁盘文件 - 外部磁盘文件排序使用归并排序,会创建一系列临时文件,最后合并
- 存在io消费
 
- 排序会将需要返回字段放入额外空间 - 全字段排序,空间占用高,但是只需要查询一次,排序后返回
- 超过空间阈值,使用排序字段和rowid进行排序,然后合并后再通过主键索引,查询后,组合最终结果,相当于结果数据集,执行了2次查询
 
 
 
- 排序字段是否索引 - 非索引字段,需要进行全表扫描
 
- 排序字段是否区分度高(分布均匀) - 需要更多的空间资源进行排序
 
优化方案
- 结果集较大,或者排序字段分布不均匀 - 分区分段进行
 
- 使用覆盖索引,避免filesort的使用 - 查询和排序使用相同索引
 
- 如果发现索引使用错误时 - 强制覆盖索引
 
实际操作
- 新建覆盖索引 - 查询索引2: user_id,order_no,update_time
- explain,未发生filesort 
思路
- 判断返回的数据集大小和查询的频繁程度
- 排序字段增加索引
- 使用覆盖索引
- 结果集大小可控的情况下,程序侧使用代码排序(内存排序),避免数据库压力
			本文由 Ivan Dong 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: Nov 2, 2023 at 10:43 am