简介
- MySQL支持两种方式的排序,FileSort和Index,其中Index的效率较高
- 他是指MySQL扫描索引本身完成排序。FileSort方式效率较低
使用Index
一般情况下ORDER BY满足两种情况会使用索引排序
- ORDER BY语句使用索引最左前列
- 使用where子句与order by 子句条件列组合满足索引最左前列
- where子句中如果出现索引的范围查询(explain中出现range)会导致order by 索引失效
建表
CREATE TABLE tblA(
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
age INT,
birth TIMESTAMP NOT NULL,
NAME VARCHAR(200)
);
INSERT INTO tblA(age,birth,NAME) VALUES(22,NOW(),'abc');
INSERT INTO tblA(age,birth,NAME) VALUES(23,NOW(),'bcd');
INSERT INTO tblA(age,birth,NAME) VALUES(24,NOW(),'def');
CREATE INDEX idx_A_ageBirth ON tblA(age,birth,NAME);
SELECT * FROM tblA;
查询如下
- 我们在age、birth、name上面建立了索引
例子
最左前列
EXPLAIN SELECT * FROM tblA WHERE age > 20 ORDER BY age;
EXPLAIN SELECT * FROM tblA WHERE age > 20 ORDER BY age,birth;
EXPLAIN SELECT * FROM tblA WHERE age > 20 ORDER BY birth;
EXPLAIN SELECT * FROM tblA WHERE age > 20 ORDER BY birth,age;
经过上面的四个例子,我们会发现只要用到了最左前列的索引,那么他就会不会用到filesort
排序(前两个)
总结
假设 KEY a_b_c(a,b,c)
order by 能使用索引最左前缀
- order by a
- order by a,b
- order by a,b,c
- order by a desc ,b desc,c desc
where使用最左前缀
where使用最左前缀定义为常量,则order by能使用索引
- where a = const order by b,c
- where a = const and b = const order by c
- where a = const order by b,c
- where a = const and b > const order by b,c
不能使用索引排序
- order by a asc , b desc , c desc : 排序不一致
- where g = const order by b,c:丢失索引a
- where a = const order by c:丢失索引b
- where a = const order by a,d:d不是索引的一部分
- where a in (…) order by b,c:对于排序来说,多个相等的条件也是范围查询
filesort
如果不在索引列上,通常,filesort有两种算法:双路排序和单路排序
双路排序
- MYSQL4.1之前是使用的双路排序,字面意思就是两次扫描磁盘,最终得到数据
- 去读行指针和order by列,对他们进行排序,然后扫描已经排序好的列表,按照列表中的值重新从列表中兑取对应的数据输入
- 从磁盘中取排序字段,在buffer进行排序,在从磁盘去其他字段
取一批数据,要对磁盘进行两次扫描,总所周知,I/O是非常耗时的,所以在mysql4.1之后,出现了第二种改进的算法,就是单路排序
单路排序
- 从磁盘读取查询需要的所有列,按照order by列在buffer对他们进行排序,然后扫描排序后的列表进行输出
- 他的效率更快一些,因为避免了第二次读取数据。并且把随机的IO变成了顺序的IO,但是他会使用更多的空间,因为他把每一行都保存在了内存中。
对比
- 总体而言,单路好过双路
- 但也存在着某种问题,单路排序要比多路排序需要更多的内存空间,有可能超出了sort_buffer的容量,导致了每次只能去sort_buffer容量大小的数据,进行排序(创建tmp文件,多路合并),排完再去sort_buffer容量大小,再排…从而导致多次IO
问题解决
为了解决单路排序的问题,我们可以用下面的措施进行解决
- 增大sort_buffer_size参数设置(他是专门用于单路排序内存大小的)
- 不管用哪种算法,提高这个参数都会提高效率,当然,要根据系统的能力去提高,因为这个参数是针对每个进程的
- 增大max_length_for_sort_data参数的设置(专门用于单词排序字段大小)
- 提高这个参数, 会增加用改进算法的概率。但是如果设的太高,数据总容量超出sort_buffer_size的概率就增大,明显症状是高的磁盘I/O活动和低的处理器使用率.
- 去掉select后面不必要的字段,如果select后面的字段多了,排序的时候也会跟着一起,很占内存,去掉没有用的
- 当Query的字段大小总和小于max_length_for_sort_data 而且排序字段不是 TEXT|BLOB 类型时,会用改进后的算法——单路排序, 否则用老算法——多路排序。
- 两种算法的数据都有可能超出sort_buffer的容量,超出之后,会创建tmp文件进行合并排序,导致多次I/O,但是用单路排序算法的风险会更大一些,所以要提高sort_buffer_size。