假如你是MySQL作者,你会如何实现order by?

大家好,我是IT周瑜,最近在研究MySQL源码,同时自己也在尝试手写一个MySQL,发现挺有趣的,因此这篇文章来跟大家一起扮演MySQL作者,一起来分析一下order by该如何实现。

大家如果对手写MySQL感兴趣,可以关注我的公众号:IT周瑜

大家先看以下SQL:

sql 复制代码
select * from t1 order by name;

以上SQL对应的需求很简单:对t1表中的全部数据按照name字段进行升序排序。

请大家思考5秒钟:如果你是MySQL作者,你会如何实现以上需求?

思路一

首先,我想到的最简单的思路是:

  1. 从磁盘中读取t1表的全部数据,并放到到一个内存List中,如果用Java,那就是一个ArrayList
  2. 然后基于此内存List,将数据按照name字段进行排序
  3. 把排序后的内存List中的数据返回给客户端
  4. 结束

思路很简单,但是我在想一个问题:如果表的数据特别多呢?如果没有足够的内存来存储所有数据呢?

也就是说,如果数据比较多,思路一就行不不通了,于是,我想到了思路二。

思路二

思路一的问题在于不能处理数据量比较大的情况,那么,我们能不能减少内存List中的数据呢,答案是可以的。

思路一的内存List中是存了一条记录的全部字段,那能不能只存部分字段呢,比如只存排序字段和主键,于是我得到思路二:

  1. 从磁盘中读取t1表的全部数据,但只读取name字段和主键字段,把读取的数据放到一个内存List中
  2. 然后基于此内存List,将数据按照name字段进行排序
  3. 然后依次取排序后内存List中的每一条记录,取出该记录的主键进行回表,得到该记录对应的完整记录,并把完整记录发送给客户端
  4. 循环执行第3步,直到遍历内存List结束

此思路的:

  • 优点是:内存List中只存了排序字段和主键,从而能够支持对更多数据进行排序
  • 缺点1:排序之后需要根据主键进行回表得到完整记录
  • 缺点2:内存不是无限的,就算只存排序字段和主键,数据量特别大的时候,内存可能仍然不够用

思路二相比较思路一:能支持更多数据的排序,但整个过程多了回表步骤。

思路三

思路二的缺点2,依然是内存不够的情况,俗话说:"内存不够,磁盘来凑",我的思路是:

  1. 如果内存够用,那就直接用内存进行排序
  2. 如果内存不够,那就需要用文件来排序

思路三是这样的:

  1. 依次遍历t1表的每条记录,取排序字段和主键字段,存到内存List中
  2. 如果内存List没有满,则继续执行第1步,如果内存List满了,则执行第3步
  3. 把List中的数据按排序字段进行排序,并把排序后的List持久化到一个临时文件中
  4. 清空内存List,继续执行第1步,直到把所有记录都遍历完,遍历完后执行第5步
  5. 最后就得到了多个临时文件,每个临时文件本质上都是一个排序之后的内存List
  6. 接下来就进行文件的归并排序,最终得到一个所有记录排序后的大临时文件,不过该临时文件中只有排序字段和主键
  7. 最后依次读取大临时文件中主键字段进行回表,得到对应的完整记录,并把完整记录发送给客户端

这样,不管表里面有多少条记录,都会先加到内存List中,内存List如果满了就持久化到临时文件,最后对所有的临时文件进行归并排序,这种思路理论上是可以处理无限多条数据的。

不过要注意,文件的归并排序,不能把文件的内容都读到内存中进行排序,这样就违背了内存不够的前提。

文件的归并排序步骤是这样的:

  1. 先取文件A和文件B
  2. 取文件A的记录A1,取文件B的记录B1
  3. 比较两条记录,假如A1小,那就将AI记录存入一个新的临时文件C中
  4. 取文件的A的记录A2,和文件B的记录B1进行比较
  5. 直到某个文件的记录被遍历完
  6. 这样文件A和文件B最终就合并为了文件C
  7. 再拿文件C和其他文件进行合并
  8. 最后只得到一个合并文件,并且是排好序的

在这个过程中每次都只占用了两条记录的内存空间。

对于思路三:

  • 优点:相比思路二,能支持更多数据的排序
  • 缺点:需要进行更多的磁盘IO,需要存临时文件,需要读临时文件

思路四

以上三种思路,要么基于内存排序,要么基于文件排序,都需要排序,那有没有不需要进行排序的呢?

那就是索引了,因为索引的本质就是对数据按指定的索引字段进行排序,所以如果排序字段有索引,那么直接取索引上现成的、已经排好序的记录直接返回给客户端就好了。

MySQL用的哪种思路?

MySQL说:"成年人不做选择,我都要"。

MySQL会自动进行选择:

  1. 思路一:叫做不回表排序
  2. 思路二和思路三:叫做回表排序
  3. 思路四:叫做索引扫描

上面提到的内存List,在MySQL中叫做sort_buffer,默认大小为256KB,可以通过sort_buffer_size参数进行配置。

好啦,以上就是order by的实现思路,大家还有其他的实现思路吗?

大家如果对手写MySQL感兴趣,可以关注我的公众号:IT周瑜

相关推荐
威视锐科技2 小时前
软件定义无线电36
网络·网络协议·算法·fpga开发·架构·信息与通信
JINX的诅咒2 小时前
CORDIC算法:三角函数的硬件加速革命——从数学原理到FPGA实现的超高效计算方案
算法·数学建模·fpga开发·架构·信号处理·硬件加速器
IT成长日记3 小时前
【MySQL基础】聚合函数从基础使用到高级分组过滤
数据库·mysql·聚合函数
草捏子5 小时前
从CPU原理看:为什么你的代码会让CPU"原地爆炸"?
后端·cpu
嘟嘟MD5 小时前
程序员副业 | 2025年3月复盘
后端·创业
胡图蛋.5 小时前
Spring Boot 支持哪些日志框架?推荐和默认的日志框架是哪个?
java·spring boot·后端
无责任此方_修行中5 小时前
关于 Node.js 原生支持 TypeScript 的总结
后端·typescript·node.js
不再幻想,脚踏实地6 小时前
MySQL(一)
java·数据库·mysql
吃海鲜的骆驼6 小时前
SpringBoot详细教程(持续更新中...)
java·spring boot·后端
迷雾骑士6 小时前
SpringBoot中WebMvcConfigurer注册多个拦截器(addInterceptors)时的顺序问题(二)
java·spring boot·后端·interceptor