MySQL中的数据排序是怎么实现的?

85 阅读2分钟

MySQL中的数据排序是怎么实现的?

重要内容

MySQL中的数据排序通常是通过 ORDER BY 子句来实现的,具体的排序原理如下

  • 如果排序字段命中索引,则利用索引排序
  • 反之,使用文件排序
    • 如果数据量少则在内存中排序,排序方式还分为单路排序或者双路排序
    • 如果数据大则利用磁盘文件进行外部排序,一般使用归并排序

扩展知识

文件排序的具体原理说明

当使用 explain 分析 SQL 发现执行计划的 extra 中包含 using filesort 的时候,说明它无法应用索引的顺序,而选择文件排序的方式

具体是在内存中还是磁盘中排序,是根据 sort_buffer 的大小来判断

# 全局设置 sort_buffer 的大小为 2MB(MySQL5.7,默认值是 1MB)
SET GLOBAL sort_buffer_size = 2*1024*1024;
  • 如果需要排序的数据比较少,则直接在内存中排序
  • 反之需要利用磁盘临时文件排序,性能就会比较差

内存排序

在内存排序中,又分为双路排序和单路排序

  • 双路排序是一种分阶段的内存排序策略。它仅将排序字段记录的唯一标识(如主键或行指针)加载到内存中完成排序,之后根据排序结果回表查询完整数据
  • 单路排序一次性将所有查询字段加载到内存中进行排序,无需回表操作,以空间换时间

通过设max_length_for_sort_data 来判断单次加载的字段总长度是否适合单路排序(默认1024字节)

  • 若查询字段总长度 ≤ max_length_for_sort_data → 采用单路排序
  • 若查询字段总长度 > max_length_for_sort_data → 采用双路排序
维度双路排序单路排序
I/O次数两次磁盘读取(排序字段+回表)一次磁盘读取(所有字段)
内存占用低(仅需存储排序字段+行ID)高(需存储所有字段)
适用场景查询字段多或包含大字段(如BLOB/TEXT)查询字段少或总长度小
效率较低(需回表查询)较高(无回表操作)
扩展性内存不足时更稳定数据量过大时易触发磁盘分块排序

磁盘文件临时排序

如果查询的数据超过 sort_buffer 说明内存放不下了,因此需要利用磁盘文件进行外部排序

一般会使用归并排序,简单理解就是将数据分为很多份文件,单独对文件排序,之后再合并成一个有序的大文件