网易首页 > 网易号 > 正文 申请入驻

自己动手写SQL执行引擎

0
分享至

前言

在阅读了大量关于数据库的资料后,笔者情不自禁产生了一个造数据库轮子的想法。来验证一下自己对于数据库底层原理的掌握是否牢靠。在笔者的github中给这个database起名为Freedom。

整体结构

既然造轮子,那当然得从前端的网络协议交互到后端的文件存储全部给撸一遍。下面是Freedom实现的整体结构,里面包含了实现的大致模块:

最终存储结构当然是使用经典的B+树结构。当然在B+树和文件系统block块之间的转换则通过Buffer(Page) Manager来进行。当然了,为了完成事务,还必须要用WAL协议,其通过Log Manager来操作。
Freedom采用的是索引组织表,通过DruidSQL Parse来将sql翻译为对应的索引操作符进而进行对应的语义操作。

MySQL Protocol结构

client/server之间的交互采用的是MySQL协议,这样很容易就可以和mysql client以及jdbc进行交互了。

query packet

mysql通过3byte的定长包头去进行分包,进而解决tcp流的读取问题。再通过一个sequenceId来在应用层判断packet是否连续。

result set packet

mysql协议部分最复杂的内容是其对于result set的读取,在NIO的方式下加重了复杂性。Freedom通过设置一系列的读取状态可以比较好的在Netty框架下解决这一问题。

row packet

还有一个较简单的是对row格式进行读取,如上图所示,只需要按部就班的解析即可。

由于协议解析部分较为简单,在这里就不再赘述。

SQL Parse

Freedom采用成熟好用的Druid SQL Parse作为解析器。事实上,解析sql就是将用文本表示 的sql语义表示为一系列操作符(这里限于篇幅原因,仅仅给出select中where过滤的原理)。

对where的处理

例如where后面的谓词就可以表示为一系列的以树状结构组织的SQL表达式,如下图所示:

当access层通过游标提供一系列row后,就可以通过这个树状表达式来过滤出符合where要求的数据。Druid采用了Parse中常用的visitor很方便的处理上面的表达式计算操作。

对join的处理

对join最简单处理方案就是对两张表进行笛卡尔积,然后通过上面的where condition进行过滤,如下图所示:

Freedom对于缩小笛卡尔积的处理

由于Freedom采用的是B+树作为底层存储结构,所以可以通过where谓词来界定B+树scan(搜索)的范围(也即最大搜索key和最小搜索key在B+树种中的位置)。考虑sql

select a.*,b.* from t_archer as a join t_rider as b where a.id>=3 and a.id<=11 b.id and b.id>=19 b.id<=31

那么就可以界定出在id这个索引上,a的scan范围为[3,11],如下图所示:

b的scan范围为[19,31],如下图所示(假设两张表数据一样,便于绘图):

scan少了从原来的15*15(一共15个元素)次循环减少到4*4次循环,即循环次数减少到7.1%

当然如果存在join condition的话,那么Freedom在底层cursor递归处理的过程中会预先过滤掉一部分数据,进一步减少上层的过滤。

B+Tree的磁盘结构 leaf磁盘结构

Freedom的B+Tree是存储到磁盘里的。考虑到存储的限制以及不定长的key值,所以会变得非常复杂。Freedom以page为单位来和磁盘进行交互。叶子节点和非叶子节点都由page承载并刷入磁盘。结构如下所示:

一个元组(tuple/item)在一个page中分为定长的ItemPointer和不定长的Item两部分。其中ItemPointer里面存储了对应item的起始偏移和长度。同时ItemPointer和Item如图所示是向着中心方向进行伸张,这种结构很有效的组织了非定长Item。

leaf和node节点在Page中的不同

虽然leaf和node在page中组织结构一致,但其item包含的项确有区别。由于Freedom采用的是索引组织表,所以对于leaf在聚簇索引(clusterIndex)和二级索引(secondaryIndex)中对item的表示也有区别,如下图所示:

其中在二级索引搜索时通过secondaryIndex通过index-key找到对应的clusterId,再通过 clusterId在clusterIndex中找到对应的row记录。
由于要落盘,所以Freedom在node节点中的item里面写入了index-key对应的pageno, 这样就可以容易的从磁盘恢复所有的索引结构了。

B+Tree在文件中的组织

有了Page结构,我们就可以将数据承载在一个个page大小的内存里面,同时还可以将page刷新到对应的文件里。有了node.item中的pageno,我们就可以比较容易的进行文件和内存结构之间的互相映射了。B+树在磁盘文件中的组织如下图所示:

B+树在内存中相对应的映射结构如下图所示:

文件page和内存page中的内容基本是一致的,除了一些内存page中特有的字段,例如dirty等。

每个索引一个B+树

在Freedom中,每个索引都是一颗B+树,对记录的插入和修改都要对所有的B+树进行操作。

B+Tree的测试

笔者通过一系列测试case,例如随机变长记录对B+树进行插入并落盘,修复了其中若干个非常诡异的corner case。

B+Tree的todo

笔者这里只是完成了最简单的B+树结构,没有给其添加并发修改的锁机制,也没有在B+树做操作的时候记录log来保证B+树在宕机等灾难性情况下的一致性,所以就算完成了这么多的工作量,距离一个高并发高可用的bptree还有非常大的距离。

Meta Data

table的元信息由create table所创建。创建之后会将元信息落盘,以便Freedom在重启的时候加载表信息。每张表的元信息只占用一页的空间,依旧复用page结构,主要保存的是聚簇索引和二级索引的信息。元信息对应的Item如下图所示:

如果想让mybatis可以自动生成关于Freedom的代码,还需要实现一些特定的sql来展现Freedom的元信息。这个在笔者另一个项目rider中有这样的实现。原理如下图所示:

实现了上述4类SQL之后,mybatis-generator就可以通过jdbc从Freedom获取元信息进而自动生成代码了。

事务支持

由于当前Freedom并没有保证并发,所以对于事务的支持只做了最简单的WAL协议。通过记录redo/undolog从而实现原子性。

redo/undo log格式协议

Freedom在每做一个修改操作时,都会生成一条日志,其中记录了修改前(undo)和修改后(redo)的运行信息,undo用来回滚,redo用来宕机recover。结构如下图所示:

WAL协议

WAL协议很好理解,就是在事务commit前将当前事务中所产生的的所有log记录刷入磁盘。Freedom自然也做了这个操作,使得可以在宕机后通过log恢复出所有的数据。

回滚的实现

由于日志中记录了undo,所以对于一个事务的回滚直接通过日志进行undo即可。如下图所示:

宕机恢复

Freedom如果在page全部刷盘之后关机,则可以通过加载page的方式获取原来的数据。但如果突然宕机,例如kill -9之后,则可以通过WAL协议中记录的redo/undo log来重新 恢复所有的数据。由于时间和精力所限,笔者并没有实现基于LSN的检查点机制。

Freedom运行

git clone https://github.com/alchemystar/Freedom.git
// 并没有做打包部署的工作,所以最简单的方法是在java编辑器里面
run alchemystar.freedom.engine.server.main

以下是笔者实际运行Freedom的例子:

join查询

delete回滚

Freedom todo

Freedom还有很多工作没有完成,例如有层次的锁机制和MVCC等,由于工作忙起来就耽搁了。于是笔者就看了看MySQL源码的实现理解了一下锁和MVCC实现原理,并写了两篇博客。比起 自己动手撸实在是轻松太多了^_^。

MVCC

https://my.oschina.net/alchemystar/blog/1927425

二阶段锁

https://my.oschina.net/alchemystar/blog/1438839

尾声

在造轮子的过程中一开始是非常有激情非常快乐的。但随着系统越来越庞大,复杂性越来越高,进度就会越来越慢,还时不时要推翻自己原来的设想并重新设计,然后再协同修改关联的所有代码,就如同泥沼,越陷越深。至此,笔者才领悟到了软件工程最重要的其实是控制复杂度!始终保持简洁的接口和优雅的设计是实现一个大型系统的必要条件。

收获与遗憾

这次造轮子的过程基本满足了笔者的初衷,通过写一个数据库来学习数据库。不仅仅是加深了理解,最重要的是笔者在写的过程中终于明白了数据库为什么要这么设计,为什么不那样设计,仅仅对书本的阅读可能并不会有这些思考与领悟。
当然,还是有很多遗憾的,Freedom并没有实现锁机制和MVCC。由于只能在工作闲暇时间写,所以断断续续写了一两个月,工作一忙就将这个项目闲置了。现在将Freedom的设计写出来,希望大家能有所收获。

END

“OSCHINA交流群”迎新啦!

可探讨技术,可天马行空~

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
最高300席!高市早苗稳了,日右翼向191国喊话,俄罗斯对日下通牒

最高300席!高市早苗稳了,日右翼向191国喊话,俄罗斯对日下通牒

离离言几许
2026-02-02 13:16:27
事发飞往上海航班!男乘客突然意识模糊!居然冲出三名专家,瑞金医生精准判断

事发飞往上海航班!男乘客突然意识模糊!居然冲出三名专家,瑞金医生精准判断

小怪吃美食
2026-02-02 16:26:28
这位老阿姨把皮草穿出了温柔又有高级感的氛围

这位老阿姨把皮草穿出了温柔又有高级感的氛围

牛弹琴123456
2026-01-19 12:10:38
释永信牵连四女星:央视名嘴、炫富被封、刘涛最冤

释永信牵连四女星:央视名嘴、炫富被封、刘涛最冤

最美的巧合
2026-01-31 03:13:30
具俊跪在大S墓前哭泣,葛斯齐爆他放弃遗产,是因为交不起遗产税

具俊跪在大S墓前哭泣,葛斯齐爆他放弃遗产,是因为交不起遗产税

无人倾听无人倾听
2026-02-01 03:33:39
沪市首份年报出炉!688230,披露重大资产重组方案!

沪市首份年报出炉!688230,披露重大资产重组方案!

证券时报e公司
2026-02-02 22:26:46
56岁窦唯现身广东一家餐厅吃饭,完全不像明星,还不如普通人好看

56岁窦唯现身广东一家餐厅吃饭,完全不像明星,还不如普通人好看

科学发掘
2026-02-02 15:40:42
美国稀土公司股价涨幅达15%

美国稀土公司股价涨幅达15%

每日经济新闻
2026-02-02 22:35:05
江苏省教育厅发布:假期不仅是孩子学业休整的驿站,更是全面发展的沃土,请理性看待校外培训,莫让假期变成“第三学期”

江苏省教育厅发布:假期不仅是孩子学业休整的驿站,更是全面发展的沃土,请理性看待校外培训,莫让假期变成“第三学期”

扬子晚报
2026-02-02 14:41:49
大S雕像揭幕:卡通形象,像风中许愿少女,在具俊晔心中永远纯真

大S雕像揭幕:卡通形象,像风中许愿少女,在具俊晔心中永远纯真

妙知
2026-02-02 23:58:43
凌晨突袭12城!上万俾路支骑摩托冲城,巴铁翼龙无人机炸烂美械

凌晨突袭12城!上万俾路支骑摩托冲城,巴铁翼龙无人机炸烂美械

感谢过往的自己
2026-02-01 12:10:05
75岁刘晓庆直播卖字再引热议:一个“福”字售价过千,四个字近4000元!工作人员称“挂中堂很有排面”

75岁刘晓庆直播卖字再引热议:一个“福”字售价过千,四个字近4000元!工作人员称“挂中堂很有排面”

大风新闻
2026-02-02 20:01:22
荷媒:马拉西亚本准备去土耳其,登机前被威尔科克斯致电拦下

荷媒:马拉西亚本准备去土耳其,登机前被威尔科克斯致电拦下

懂球帝
2026-02-02 21:36:02
银翅劫 8:官差扣,怒声扬

银翅劫 8:官差扣,怒声扬

金昔说故事
2026-02-02 20:03:19
军权交接仪式刚结束,委代总统就收到命令:立刻驱逐中国外交官

军权交接仪式刚结束,委代总统就收到命令:立刻驱逐中国外交官

诗酒趁的年华
2026-02-01 19:48:09
因嫌1500元返程机票太贵,东北男子连偷8辆车

因嫌1500元返程机票太贵,东北男子连偷8辆车

有书
2026-02-01 16:00:06
小菲筱梅带箖玥广州旅游,玥儿长发飘飘,打扮时尚,侧脸好像大S

小菲筱梅带箖玥广州旅游,玥儿长发飘飘,打扮时尚,侧脸好像大S

丁丁鲤史纪
2026-02-02 17:36:57
男人出不出轨,取决于有没有机会,女人出不出轨,取决于她的男人

男人出不出轨,取决于有没有机会,女人出不出轨,取决于她的男人

热心市民小黄
2026-02-03 00:19:45
当不成总统了?美70人身亡,特朗普下令“中止行动”,美军舰出动

当不成总统了?美70人身亡,特朗普下令“中止行动”,美军舰出动

窥史
2026-02-02 18:20:03
东体:因为U23男足小组出线,徐彬才满足了狼队外卡要求

东体:因为U23男足小组出线,徐彬才满足了狼队外卡要求

懂球帝
2026-02-02 12:31:07
2026-02-03 02:12:49
开源中国 incentive-icons
开源中国
每天为开发者推送最新技术资讯
7578文章数 34499关注度
往期回顾 全部

科技要闻

阿里筑墙,腾讯寄生,字节偷家

头条要闻

周生生足金挂坠戴1天被刮花 检测后发现含铁、银、钯

头条要闻

周生生足金挂坠戴1天被刮花 检测后发现含铁、银、钯

体育要闻

澳网男单决赛,属于阿尔卡拉斯的加冕仪式

娱乐要闻

57岁音乐人袁惟仁去世,家属发文悼念

财经要闻

金银暴跌 全球股市遭遇“黑色星期一”

汽车要闻

雷克萨斯LC500将于今年底停产 "最美雷克萨斯"谢幕

态度原创

本地
家居
亲子
公开课
军事航空

本地新闻

云游中国|拨开云雾,巫山每帧都是航拍大片

家居要闻

现代几何彩拼 智焕童梦居

亲子要闻

萌娃哄生气的妈妈,人小鬼大逗得妈妈生不起气来了

公开课

李玫瑾:为什么性格比能力更重要?

军事要闻

委内瑞拉外长会见美外交使团团长

无障碍浏览 进入关怀版