mysql order by是怎么工作的

查询语句:select city,name,age from table where city='杭州' order by name limit 1000;
上面这条sql语句的执行流程,怎么执行,以及什么参数会影响执行的行为
 
首先给city字段加索引之后,使用explain命令查看语句执行情况,会发现有using filesort,这就是表示要排序。
mysql会给每个线程分配一块内存用于排序,称为sort_buffer
 
以上这条语句的执行流程:
1、初始化sort_buffer,确定放入了name age city三个字段
2、从索引city找到第一个满足city=杭州的条件的主键id,
3、到主键id索引取出整行,取name、city、age三个字段的值,存入sort_buffer中
4、从索引city取下一个记录的主键id
5、重复3、4直到city不满足查询条件为止
6、对sort_buffer中的数据按照字段name做快速排序
7、按照排序结果取前1000行返回客户端
 
 
sort_buffer_size就是mysql为排序开辟的内存(sort_buffer)的大小,如果要排序的数据量小于sort_buffer_size,排序就在内存中完成,如果排序数据量太多,内存放不下,则不得不利用磁盘临时文件辅助排序
 
虽然在定义字段的时候使用varchar(18),但在排序过程中还是要按照实际长度来分配空间的
 
上面的算法过程中,只对原标数据读了一遍,剩下的操作都是在sort_buffer和临时文件总执行的,这个算法有个问题就是,如果查询要返回很多字段的话,那么sort_buffer里面要放的字段数太多,这样内存里能够同时放下的行数很少,要分成很多个临时文件,排序的性能就差
所以单行很多,这个方法效率就不好
 
SET max_length_for_sort_data = 16;
设置这个参数,如果单行的长度超过这个值,mysql就认为单行太大,要换一个算法
设置这个参数,整个执行流程就变了样子
1、初始化sort_buffer
2、从索引city找到第一个满足city=杭州条件的主键id
3、到主键id索引取出整行,取name、id这两个字段,存放sort_buffer中
4、从索引city取下一个记录id
5、重复3、4
这种执行流程又称为rowid排序
 
 
这两种排序得出的结论:
1、mysql实在是担心排序内存太小,会影响排序效率,才会采用rowid排序算法,这样排序过程中一次可以排序更多行,但是需要再回到原表去取数据
 
2、mysql认为内存足够大,会优先选择全字段排序,把需要的字段都放到sort_buffer中,这样排序后就会之间从内存里面返回查询结果了,不会再回到原表去取数据
 
这就体现了mysql的一个设计思想:如果内存够,就要多利用内存,尽量减少磁盘访问
 
对于innodb表来说,rowid排序会要求回表多造成磁盘读,因此不会被优先选择
 
所以了解了以上两种算法,才发现排序对于mysql是一个成本比较高的操作,其实,并不是所有的order by语句都需要排序,从上面分享的执行结果,我们可以看到,mysql之所以需要生成临时表,并且临时表上做排序操作,其原因是原来的数据都是无序的
 
所以,我们修改刚才的表索引
alter table t add index city_user(city, name);
创建联合索引
再次使用explain查看语句就会发现没有using filesort
 
这就是为什么在很多优化的文章中出现如果使用explain命令有using filesort就需要优化的原因了
 
以上就是学习极客时间中mysql实战中的文章,具体可以去学习,我只是根据自己的理解做个笔记。
 

posted @ 2019-02-18 21:04  魏什么魏什么啊  阅读(638)  评论(0编辑  收藏  举报