由 mysql 中的一次慢查询,来看 order by 的文件排序和索引排序

由 mysql 中的一次慢查询,来看 order by 的文件排序和索引排序

说明

  1. @author JellyfishMIX - github / blog.jellyfishmix.com
  2. LICENSE GPL-2.0

慢查询

笔者在之前工作期间,写过一个列表的查询需求,引发了线上的慢查询问题(一般情况下,我们把查询时间超过 1s 的查询称为慢查询,不同团队定义不同)。

数据表量级大概在 3800w 行。敏感信息已屏蔽,且字段名非真实字段名,能表达意思即可。我们用简单的字段来复现问题场景。

content 要查寻的内容

type 类型,可以理解为 where 中的查询条件

create_time 创建时间

audit_time 审核时间

引发慢查询的 sql 如下:

select content from demo_table where create_time >= ${startTime} and create time < ${endtTime} and type = 2 order by audit_time desc;

请注意,${} 这里表示是一个变量,执行 sql 的时候会替换成实际的值。另外这是示意 sql,不要考虑 sql 注入风险等问题,实际的 sql 比这个严谨。

create_time 加了索引,audit_time 是没有索引的,order by audit_time 最后走了文件排序,这个文件排序导致了慢查询。

解决方案是,排序字段换成了使用了索引的 create_time 字段,利用索引的有序性,避免走文件排序。

文件排序 filesort

filesort 并不是说通过磁盘文件进行排序,只是告诉我们进行了一个排序操作。即在 MySQL Query Optimizer 所给出的执行计划(通过 EXPLAIN 命令查看)中被称为 filesort

文件排序是通过相应的排序算法,将取得的数据在内存中进行排序。mysql 需要将数据在内存中进行排序,所使用的内存区域是通过 sort_buffer_size 系统变量所设置的排序区。这个排序区是每个 thread 独享的,所以说可能在同一时刻在MySQL 中可能存在多个 sort buffer 内存区域。

在 mysql 中 filesort 的实现算法有两种:

  1. 双路排序:根据查询条件取出排序字段,和可以直接定位行数据的行指针信息,这也是第一次 IO。然后在 sort buffer 中进行排序。把行指针排序好后,要再进行一次 IO 将具体的行查询字段读出,才能返回结果。

  2. 单路排序:根据查询条件取出排序字段和需要查询的行字段(一次 IO),然后在 sort buffer 中进行排序。排序后就可以返回结果了。

在 mysql 4.1 版本之前只有双路排序,单路排序是从 mysql 4.1 开始推出的改进算法。单路排序的主要目的,为了把双路排序中需要两次 IO,变成只需要一次 IO,但相应也会耗用更多的 sortbuffer 空间。mysql 4.1 及之后的版本同时支持双路排序与单路排序。

mysql 主要通过比较我们所设定的系统参数 max_length_for_sort_data 的大小,和 query 语句所需取出的字段类型大小总和,来判断使用哪一种排序算法。如果 max_length_for_sort_data 足够大,则使用速度更快的单路排序,反之使用所需内存小的双路排序。所以如果想优化文件排序的速度,需要注意 max_length_for_sort_data 参数的设置。

当表中数据量非常大时,更推荐的做法是,不要使用文件排序,给 order by 的排序字段加索引。

索引排序

在使用 explain 分析查询的时候,利用有序索引获取有序数据显示 Using index,而文件排序显示 Using filesort

InnoDB 中的索引是 B+ 树结构,B+ 树中的索引是有序的。因此可以通过给排序字段加索引,利用索引的有序性,来加快排序速度。

应注意的

当表中数据量很大时,应当注意 order by 的文件排序的时间消耗,预估到 order by 可能造成的慢查询风险,对 order by 的条件字段加索引,利用索引的有序性来避免文件排序。

慢查询棘手的地方在于测试环节很难发现,因为测试环境的数据量通常比生产环境的数据量级少很多。在数据量不大的情况下,慢查询问题很难通过测试发现。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
如果你的MySQL InnoDB表,where字段有索引,但是在使用order by聚集索引进行排序时仍然很慢,可能是由于以下几个原因导致的: 1. 索引选择不当:虽然你的where字段有索引,但是在order by聚集索引排序时,可能没有使用到合适的索引。使用EXPLAIN语句来查看查询计划,确认是否使用了正确的索引。你可以尝试创建一个包含where字段和排序字段的复合索引,以提高查询效率。 2. 数据量过大:如果表的数据量非常大,即使有合适的索引,仍然可能导致排序操作变慢。考虑通过分页查询或者限制结果集的大小来减少排序的数据量。 3. 硬件性能问题:如果服务器硬件配置较低,例如内存不足或者磁盘IO性能不佳,也可能导致排序操作变慢。确保服务器具备足够的资源以支持高效的排序操作。 4. 查询优化:请检查SQL语句是否存在其他影响性能的因素,例如过多的关联表、不必要的数据类型转换等。优化查询语句可以提高整体性能。 5. 调整配置参数:针对InnoDB引擎,你还可以尝试调整一些相关的配置参数来优化排序操作。例如,增加sort_buffer_size参数的值,提高排序缓冲区的大小。 总之,解决MySQL InnoDB的where字段有索引,但是order by聚集索引排序很慢的问题,需要综合考虑索引选择、数据量、硬件性能、查询优化和配置参数等方面的因素。通过合理的索引设计、优化查询语句和调整配置参数,可以提高排序操作的性能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JellyfishMIX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值