#时光荏苒,初心不变# 导读:同学,你好。欢迎你能来和我一起学习MySQL。我希望以后你可以和我共同努力,我们每天进步一点点,自古有句老话:“梅花香自苦寒来,宝剑锋从磨砺出”让我们一起加油吧。
你要知道,你周围的任何东西都会被抢走,只有你的知识是别人抢不走的。一句话,虽然学习很苦,学习很累,但是我们还是需要给自己找一份理由:吃这份苦是为了自己,不是为了别人。
要始终记住:学习是为自己淘金。如果觉得累,觉得看不下去,那么你退出去去尽情地玩耍去吧。但是你要明白,你在玩耍不代表别人也在玩耍。
order by 典型面试题
下面的Question,我希望你可以将文章收藏,然后平时没事了拿出来问问自己掌握了吗 ?如果对以下知识点有不清楚的,要踊跃的在评论区提出问题,我会第一时间为你解答。
Q:平时开发的时候一定遇到过根据某个字段排序查询的情况吧,可以说说MySQL的排序原理吗?
A:根据MySQL排序原理划分的话,MySQL排序有两种方式,一个是通过有序索引直接返回数据,另一种是通过Filesort进行排序数据。
Q:一条SQL语句你是怎么确定它用的是哪种排序呢?
A:可以使用Explain或desc SQL语句来查看,在输出信息中Extra字段会具体显示用了哪种排序,如果Extra显示Using index,则表示是通过有序索引直接返回有序数据的。如果显示Using filesort,则表示SQL是通过Filesort进行排序返回数据的。
Q:既然你提到了Filesort,可以说说FIlesort的排序操作,是否都是在磁盘中完成的呢?
A:MySQL 中的 Filesort 并不一定是在磁盘文件中进行排序的,也有可能在内存中排序,内存排序还是磁盘排序取决于排序的数据大小和 sort_buffer_size 配置的大小。如果 “排序的数据大小” < sort_buffer_size: 内存排序。如果 “排序的数据大小” > sort_buffer_size: 磁盘排序。
Q:那么你是怎么确定使用 Filesort 排序的 SQL 是在内存还是在磁盘中进行的排序操作?
A:可以使用trace进行分析查看(MySQL优化:学会使用show profile和trace分析慢查询)重点关注:number_of_tmp_files这个参数。如果=0,表示排序过程中没有使用临时文件,是在内存中完成排序的,如果>0,则表示排序过程中使用了临时文件,是在磁盘文件中进行排序的。
上图使用的是内存排序,下面我们看看这些字段的含义:
rows:预计扫描的行数。examined_rows:参与排序的行number_of_tmp_files:使用临时文件的个数sort_buffer_size:sort_buffer 的大小sort_mode:排序模式
再看一个用到临时文件的例子,如下图,因为 number_of_tmp_files 等于 7,所以表示使用的是磁盘排序。对于 number_of_tmp_files 等于 7 表示该 SQL 将需要排序的数据分为 7 份,然后每份单独排序,再存放在 7 个临时文件中,最后把 7 个临时文件合并成一个大的有序文件。
Q:了解的还挺多的嘛,那么可以聊聊Filesort有几种排序模式吗?
A:可以的,总共有三种模式,官网order by optimization一章节有详细介绍。
< sort_key, rowid >双路排序(又叫回表排序模式):是首先根据相应的条件取出相应的排序字段和可以直接定位行数据的行 ID,然后在 sort buffer 中进行排序,排序完后需要再次取回其它需要的字段;
< sort_key, additional_fields >单路排序:是一次性取出满足条件行的所有字段,然后在sort buffer中进行排序;
< sort_key, packed_additional_fields >打包数据排序模式:打包数据排序模式是单路排序的一种升级模式,与单路排序相似,区别是将 char 和 varchar 字段存到 sort buffer 中时,更加紧缩。
Q:MySQL是根据什么判断使用哪种排序模式。
A:MySQL 通过比较系统变量 max_length_for_sort_data 的大小和需要查询的字段总大小来判断使用哪种排序模式。如果 max_length_for_sort_data 比查询字段的总长度大,那么使用 < sort_key, additional_fields >排序模式;如果 max_length_for_sort_data 比查询字段的总长度小,那么使用 排序模式。
Q:为什么要添加 max_length_for_sort_data 这个参数让排序使用不同的排序模式呢?限定只用一种排序模式不行吗?可以聊聊双路排序和单路排序的区别吗?(阿里经典面试题)
A:比如这条SQLselect a,c,d from t1 where a=1000 order by d;
单路排序中它是这样执行的:
从索引 a 找到第一个满足 a = 1000 条件的主键 id根据主键 id 取出整行,取出 a、c、d 三个字段的值,存入 sort_buffer 中从索引 a 找到下一个满足 a = 1000 条件的主键 id重复步骤 2、3 直到不满足 a = 1000对 sort_buffer 中的数据按照字段 d 进行排序返回结果给客户端
双路排序是这样执行的:
从索引 a 找到第一个满足 a = 1000 的主键 id根据主键 id 取出整行,把排序字段 d 和主键 id 这两个字段放到 sort buffer 中从索引 a 取下一个满足 a = 1000 记录的主键 id重复 3、4 直到不满足 a = 1000对 sort_buffer 中的字段 d 和主键 id 按照字段 d 进行排序遍历排序好的 id 和字段 d,按照 id 的值回到原表中取出 a、c、d 三个字段的值返回给客户端其实对比两个排序模式,单路排序会把所有需要查询的字段都放到 sort buffer 中,而双路排序只会把主键和需要排序的字段放到 sort buffer 中进行排序,然后再通过主键回到原表查询需要的字段。
如果 MySQL 排序内存配置的比较小并且没有条件继续增加了,可以适当把 max_length_for_sort_data 配置小点,让优化器选择使用 rowid 排序算法,可以在 sort_buffer 中一次排序更多的行,只是需要再根据主键回到原表取数据。
所以 MySQL 通过 max_length_for_sort_data 这个参数来控制排序,在不同场景使用不同的排序模式,从而提升排序效率。
Q:可以说说innodb_sort_buffer_size,myisam_sort_buffer_size,sort_buffer_size这三个参数有何区别吗?
A:你好,innodb_sort_buffer_size :指定创建 InnoDB 索引期间用于排序数据的排序缓冲区的大小 这个参数只会在创建索引的过程中被使用,不会用在后面的维护操作; myisam_sort_buffer_size:MyISAM表发生变化时重新排序所需的缓冲; sort_buffer_size:每个session 分配的排序缓存。
章尾总结
我们这篇文章主要通过面试题的方法,学习了MySQL中order by的排序原理。
在下一篇中我们会重点讲解order by 和 group by的优化方法。
学习是为你自己学习,好了,今天又进步不少了。关闭电脑放下手机,除去大吃大喝一顿吧,周末快乐。
写在最后:如果大家觉得本篇对你有帮助,记得关注和转发哦,如果后期你还想学习这篇文章,那么你千万要记得收藏哦。