Mysql-05 Using filesort文件排序原理

1、先说结论:

        MySQL 系统变量 max_length_for_sort_data默认1024字节

        如果需要查询字段的总长度 < max_length_for_sort_data ,使用单路排序模式;

        如果需要查询字段的总长度 > max_length_for_sort_data ,使用双路排序模·式

2、查询示例

示例表 记录数100000+
CREATE TABLE `employees` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(24) NOT NULL DEFAULT '' COMMENT '姓名',
  `age` int(11) NOT NULL DEFAULT '0' COMMENT '年龄',
  `position` varchar(20) NOT NULL DEFAULT '' COMMENT '职位',
  `hire_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入职时间',
  PRIMARY KEY (`id`),
  KEY `idx_name_age_position` (`name`,`age`,`position`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='员工记录表';

EXAIN select * from employees where name = 'dongzhuo' order by position;

3、trace工具

set session optimizer_trace="enabled=on",end_markers_in_json="on";  --开启trace
set session optimizer_trace="enabled=off";    --关闭trace

4、filesort排序方式

1)单路排序

是一次性取出满足条件行的所有字段,然后在sort buffer中进行排序;用trace工具可以看到sort_mode信息里显示< sort_key, additional_fields >或者< sort_key, packed_additional_fields >

select * from employees where name = 'dongzhuo' order by position;
select * from information_schema.OPTIMIZER_TRACE;

Mysql-05 Using filesort文件排序原理_第1张图片

排序过程 :

  1. 从索引name找到第一个满足 name = ‘dongzhuo’ 条件的主键 id
  2. 根据主键 id 取出整行,取出所有字段的值,存入 sort_buffer 中
  3. 从索引name找到下一个满足 name = ‘dongzhuo’ 条件的主键 id
  4. 重复步骤 2、3 直到不满足 name = ‘dongzhuo’
  5. 对 sort_buffer 中的数据按照position字段进行排序
  6. 返回结果给客户端

2)双路排序

双路排序(又叫回表排序模式):先根据相应的条件取出相应的排序字段和可以直接定位行数据的行 ID,然后在 sort buffer 中进行排序,排序完后再取回其它需要的字段;用trace工具可以看到sort_mode信息里显示< sort_key, rowid >(我用的MySQL8,这里有点问题待验证)

set max_length_for_sort_data = 10;    --employees表所有字段长度总和肯定大于10字节
select * from employees where name = 'dongzhuo' order by position;
select * from information_schema.OPTIMIZER_TRACE;

Mysql-05 Using filesort文件排序原理_第2张图片

排序过程:

  1. 从索引 name 找到第一个满足 name = ‘dongzhuo’ 的主键id
  2. 根据主键 id 取出整行,把排序字段 position 和主键 id 这两个字段放到 sort buffer 中
  3. 从索引 name 取下一个满足 name = ‘dongzhuo’ 记录的主键 id
  4. 重复 3、4 直到不满足 name = ‘dongzhuo’
  5. 对 sort_buffer 中的position字段和主键 id按照position字段进行排序
  6. 遍历排好序的 id 和 position,按照 id 回表取出所有字段的值返回给客户端

总结:

1、单路排序把所有需要查询的字段放入sort_buffer中然后使用排序字段排序;双路排序只把id和需要排序的字段放入sort_buffer中,然后使用排序字段排序,再根据id回表查询需要的字段

2、双路排序一次可以排序更多的行

3、单路排序后直接从内存中返回排序结果

4、根据内存情况,通过 max_length_for_sort_data 参数来控制排序,在不同场景使用不同的排序模式提升效率。

5、全部使用sort_buffer内存排序一般情况下效率会高于磁盘文件排序

你可能感兴趣的:(mysql,数据库)