Using filesort
当语句中使用到 order by 排序时,尽可能遵照索引键的最佳左前缀,在索引列上进行排序操作。
如果排序字段 不能通过索引树的排序时 就会出现 using filesort 文件排序。如下图执行语句。
EXPLAIN SELECT * from employees ORDER BY name
FileSort有两种算法,双路排序和单路排序(mysql4.1之前只有双路排序)。接下来本文就这两种算法进行分析。
sort_buff
MySQL 为每个线程各维护了一块内存区域 sort_buffer ,用于进行排序。sort_buffer 的大小可以通过 sort_buffer_size 来设置。如果加载的记录总大小小于 sort_buffer_size 便使用 sort_buffer 排序;如果超过则使用 sort_buffer + 临时文件进行排序。
这是排序时,存储数据的内存结构,先有个印象方便后面理解。**
单路排序
是一次性取出满足条件行的所有字段,然后在sort buffer中进行排序;用trace工具可 以看到sort_mode信息里显示< sort_key, additional_fields >或者< sort_key, packed_additional_fields >
排序过程
- 根据查询条件找第一个满足条件的数据行
- 取出所有字段的值,存入 sort_buffer 中
- 根据查询条件找到下一个满足 条件的数据行
- 重复步骤 2、3 直到查出所有满足条件的数据
- 对 sort_buffer 中的数据按照 排序字段 进行排序
- 返回结果给客户端
- 优点:查询快,执行过程简单
- 缺点:需要的空间大。
双路排序(回表排序)
是首先根据相应的条件取出相应的排序字段和可以直接定位行 数据的行 ID,然后在 sort buffer 中进行排序,排序完后需要再次取回其它需要的字段;
用trace工具 可以看到sort_mode信息里显示< sort_key, rowid >
- 根据查询条件找第一个满足条件的数据行
- 把排序字段 和主键 放到 sort buffer 中
- 根据查询条件找到下一个满足 条件的数据行
- 重复步骤 2、3 直到查出所有满足条件的数据
- 对 sort_buffer 中的排序字段 和主键 按照字段 排序字段 进行排序
- 遍历排序好的 主键 和 排序字段 ,按照 主键 进行回表(这时已经是有序状态)
- 返回数据到客户端
- 优点:所需的空间更小。
- 缺点:会产生更多次数的回表查询,查询可能会慢一些。
单/双路排序的选择
排序方式的选择是由 max_length_for_sort_data参数与返回记录字段总长度决定的,如果用于排序的单条记录字段长度 <= max_length_for_sort_data 使用单路排序;反之则使用 双路 排序。
实战
trace工具使用: MySQL Optimizer 分析(trace 工具)
1.max_length_for_sort_data = 1024 大于字段总长度 将使用 单路排序
执行如下语句 用trace进行分析
set session optimizer_trace=”enabled=on”,end_markers_in_json=on;
SELECT * from employees ORDER BY age LIMIT 10;
select * from information_schema.OPTIMIZER_TRACE;
结果:
{ |
结论:由trace 倒数第 8 行 “sort_mode”: “<sort_key, additional_fields>” 得出为单路排序
2.将 max_length_for_sort_data 设置为 10,employees表所有字段长度总和肯定大于10字节 ,那么字段总长度大于max_length_for_sort_data 将使用 双路排序。
set max_length_for_sort_data = 10;
SELECT * from employees ORDER BY age LIMIT 10;
select * from information_schema.OPTIMIZER_TRACE;
trace结果
{ |
结论:由trace 倒数第 8 行 “sort_mode”: “<sort_key, rowid>” 得出为双路排序
对比及选择
其实对比两个排序模式,单路排序会把所有需要查询的字段都放到 sort buffer 中,而双路排序只会把主键 和需要排序的字段放到 sort buffer 中进行排序,然后再通过主键回到原表查询需要的字段。
如果 MySQL 排序内存 sort_buffer 配置的比较小并且没有条件继续增加了,可以适当把 max_length_for_sort_data 配置小点,让优化器选择使用双路排序算法,可以在sort_buffer 中一次排序更 多的行,只是需要再根据主键回到原表取数据。
如果 MySQL 排序内存有条件可以配置比较大,可以适当增大 max_length_for_sort_data 的值,让优化器 优先选择全字段排序(单路排序),把需要的字段放到 sort_buffer 中,这样排序后就会直接从内存里返回。
⚠️如果全部使用sort_buffer内存排序一般情况下效率会高于磁盘文件排序,但不能因为这个就随便增 大sort_buffer(默认1M),mysql很多参数设置都是做过优化的,不要轻易调整。
若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏
扫描二维码,分享此文章