-- 示例表 CREATE TABLE `employees` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(24) NOT NULL DEFAULT '' COMMENT '姓名', `age` int(20) NOT NULL DEFAULT '0' COMMENT '年龄', `position` varchar(20) NOT NULL DEFAULT '' COMMENT '职位', `hire_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '入职时间', PRIMARY KEY (`id`), KEY `idx_name_age_position` (`name`,`age`,`position`) USING BTREE, KEY `idx_age` (`age`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=136326 DEFAULT CHARSET=utf8 COMMENT='员工表'
EXPLAIN select * from employees WHERE name='LiLei' and position='dev' order by age;
利用最左前缀法则:中间字段不能断,所以查询用到了name索引,从key_len=74也能看出,age索引列用在排序的过程当中,由于Extra字段里没有using filesort。web
EXPLAIN select * from employees WHERE name='LiLei' order by position;
从explain的执行结果来看:key_len=74, 查询使用name索引,因为用了position进行排序,跳过了age,出现了Using filesort。sql
EXPLAIN select * from employees WHERE name='LiLei' order by age,position;
查找只用到了name索引,age和position用于排序,无Using filesort。编程
EXPLAIN select * from employees WHERE name='LiLei' order by position,age;
和上一个case不一样的是,Extra中出现了Using filesort,由于索引的建立顺序为name,age,position,可是排序的时候age和position颠倒了位置。json
EXPLAIN select * from employees WHERE name='LiLei' order by age asc, position desc;
虽然排序的字段和联合索引顺序是同样的,且order by是默认升序,这里position desc是降序,致使与索引的排序方式不一样,从而产生Using filesort。Mysql8以上版本有降序索引能够支持该种查询方式。后端
EXPLAIN select * from employees WHERE name in('LiLei', 'zhuge') order by age, position ;
对于排序来讲,多个相等条件也是范围查询。缓存
EXPLAIN select * from employees WHERE name > 'a' order by name;
能够用覆盖索引优化session
EXPLAIN select name,age,position from employees WHERE name > 'a' order by name;
EXPLAIN select * from employees where name='LiLei' order by position;
查看这条sql对应trace结果(只展现排序部分):app
set session optimizer_trace="enabled=on",end_markers_in_json=on; ‐‐开启trace select * from employees where name = 'LiLei' order by position; select * from information_schema.OPTIMIZER_TRACE; { "join_execution": { --sql执行阶段 "select#": 1, "steps": [ { "filesort_information": [ { "direction": "asc", "table": "`employees`", "field": "position" } ] /* filesort_information */, "filesort_priority_queue_optimization": { "usable": false, "cause": "not applicable (no LIMIT)" } /* filesort_priority_queue_optimization */, "filesort_execution": [ ] /* filesort_execution */, "filesort_summary": { --文件排序信息 "rows": 1, --预计扫描行数 "examined_rows": 1, --参与排序的行 "number_of_tmp_files": 0, --使用临时文件的个数,这个值为0表明所有使用sort_buffer内存排序,不然使用磁盘文件排序 "sort_buffer_size": 200704, --排序缓存的大小 "sort_mode": "<sort_key, additional_fields>" --排序方式,这里用的单路排序 } /* filesort_summary */ } ] /* steps */ } /* join_execution */ }
修改max_length_for_sort_data=10机器学习
set max_length_for_sort_data = 10; --employees表全部字段长度总和确定大于10字节 select * from employees where name = 'LiLei' order by position; select * from information_schema.OPTIMIZER_TRACE; { "join_execution": { "select#": 1, "steps": [ { "filesort_information": [ { "direction": "asc", "table": "`employees`", "field": "position" } ] /* filesort_information */, "filesort_priority_queue_optimization": { "usable": false, "cause": "not applicable (no LIMIT)" } /* filesort_priority_queue_optimization */, "filesort_execution": [ ] /* filesort_execution */, "filesort_summary": { "rows": 1, "examined_rows": 1, "number_of_tmp_files": 0, "sort_buffer_size": 53248, "sort_mode": "<sort_key, rowid>" --排序方式为双路排序 } /* filesort_summary */ } ] /* steps */ } /* join_execution */ }
对比这两个排序模式,单路排序会把全部的须要查询的字段数据都放到sort_buffer中,而双路排序只会把主键id和须要排序的字段放到sort_buffer中进行排序,而后再经过主键id 回到原表 查询须要的字段数据。MySQL经过max_length_for_sort_data这个参数来控制排序,在不一样场景下使用不一样的排序模式,从而提高排序效率。编程语言
还没关注个人公众号?