大家好,我是IT周瑜,最近在研究MySQL源码,同时自己也在尝试手写一个MySQL,发现挺有趣的,因此这篇文章来跟大家一起扮演MySQL作者,一起来分析一下order by该如何实现。
大家如果对手写MySQL感兴趣,可以关注我的公众号:IT周瑜
大家先看以下SQL:
sql
select * from t1 order by name;
以上SQL对应的需求很简单:对t1表中的全部数据按照name字段进行升序排序。
请大家思考5秒钟:如果你是MySQL作者,你会如何实现以上需求?
思路一
首先,我想到的最简单的思路是:
- 从磁盘中读取t1表的全部数据,并放到到一个内存List中,如果用Java,那就是一个ArrayList
- 然后基于此内存List,将数据按照name字段进行排序
- 把排序后的内存List中的数据返回给客户端
- 结束
思路很简单,但是我在想一个问题:如果表的数据特别多呢?如果没有足够的内存来存储所有数据呢?
也就是说,如果数据比较多,思路一就行不不通了,于是,我想到了思路二。
思路二
思路一的问题在于不能处理数据量比较大的情况,那么,我们能不能减少内存List中的数据呢,答案是可以的。
思路一的内存List中是存了一条记录的全部字段,那能不能只存部分字段呢,比如只存排序字段和主键,于是我得到思路二:
- 从磁盘中读取t1表的全部数据,但只读取name字段和主键字段,把读取的数据放到一个内存List中
- 然后基于此内存List,将数据按照name字段进行排序
- 然后依次取排序后内存List中的每一条记录,取出该记录的主键进行回表,得到该记录对应的完整记录,并把完整记录发送给客户端
- 循环执行第3步,直到遍历内存List结束
此思路的:
- 优点是:内存List中只存了排序字段和主键,从而能够支持对更多数据进行排序
- 缺点1:排序之后需要根据主键进行回表得到完整记录
- 缺点2:内存不是无限的,就算只存排序字段和主键,数据量特别大的时候,内存可能仍然不够用
思路二相比较思路一:能支持更多数据的排序,但整个过程多了回表步骤。
思路三
思路二的缺点2,依然是内存不够的情况,俗话说:"内存不够,磁盘来凑",我的思路是:
- 如果内存够用,那就直接用内存进行排序
- 如果内存不够,那就需要用文件来排序
思路三是这样的:
- 依次遍历t1表的每条记录,取排序字段和主键字段,存到内存List中
- 如果内存List没有满,则继续执行第1步,如果内存List满了,则执行第3步
- 把List中的数据按排序字段进行排序,并把排序后的List持久化到一个临时文件中
- 清空内存List,继续执行第1步,直到把所有记录都遍历完,遍历完后执行第5步
- 最后就得到了多个临时文件,每个临时文件本质上都是一个排序之后的内存List
- 接下来就进行文件的归并排序,最终得到一个所有记录排序后的大临时文件,不过该临时文件中只有排序字段和主键
- 最后依次读取大临时文件中主键字段进行回表,得到对应的完整记录,并把完整记录发送给客户端
这样,不管表里面有多少条记录,都会先加到内存List中,内存List如果满了就持久化到临时文件,最后对所有的临时文件进行归并排序,这种思路理论上是可以处理无限多条数据的。
不过要注意,文件的归并排序,不能把文件的内容都读到内存中进行排序,这样就违背了内存不够的前提。
文件的归并排序步骤是这样的:
- 先取文件A和文件B
- 取文件A的记录A1,取文件B的记录B1
- 比较两条记录,假如A1小,那就将AI记录存入一个新的临时文件C中
- 取文件的A的记录A2,和文件B的记录B1进行比较
- 直到某个文件的记录被遍历完
- 这样文件A和文件B最终就合并为了文件C
- 再拿文件C和其他文件进行合并
- 最后只得到一个合并文件,并且是排好序的
在这个过程中每次都只占用了两条记录的内存空间。
对于思路三:
- 优点:相比思路二,能支持更多数据的排序
- 缺点:需要进行更多的磁盘IO,需要存临时文件,需要读临时文件
思路四
以上三种思路,要么基于内存排序,要么基于文件排序,都需要排序,那有没有不需要进行排序的呢?
那就是索引了,因为索引的本质就是对数据按指定的索引字段进行排序,所以如果排序字段有索引,那么直接取索引上现成的、已经排好序的记录直接返回给客户端就好了。
MySQL用的哪种思路?
MySQL说:"成年人不做选择,我都要"。
MySQL会自动进行选择:
- 思路一:叫做不回表排序
- 思路二和思路三:叫做回表排序
- 思路四:叫做索引扫描
上面提到的内存List,在MySQL中叫做sort_buffer,默认大小为256KB,可以通过sort_buffer_size参数进行配置。
好啦,以上就是order by的实现思路,大家还有其他的实现思路吗?
大家如果对手写MySQL感兴趣,可以关注我的公众号:IT周瑜