-- 示例表 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這個參數來控制排序,在不一樣場景下使用不一樣的排序模式,從而提高排序效率。編程語言
還沒關注個人公衆號?