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 说明内存放不下了,因此需要利用磁盘文件进行外部排序
一般会使用归并排序,简单理解就是将数据分为很多份文件,单独对文件排序,之后再合并成一个有序的大文件