数据库是怎么工作的?
当你打开这篇文章的时候你一定也好奇:
- SQL语句为什么能对数据库操作
- 事务回滚是怎么滚的?
- 数据是怎么被保存到硬盘里的?
- …
接下来我们将一步步搭建一个框架并逐渐完善,并尝试着把这些问题讲明白。
我选择基于 SQLite ,因为 SQLite 体积小又功能齐全,整个数据库就存储在一个文件中。
我认为可以以此为起点以小见大,启发大家对数据库有更多的思考。
一个 SQL 语句需要经过一连串的过程才能检索或修改数据。
- 前端包括:
- tokenizer 词法解析器
- parser 语法解析器
- code generator 代码生成器
前端输入一个 SQL 查询,输出为 SQLite 虚拟机字节码。字节码本质上就是可以在数据库上运行的程序。
- 后端包括:
- Virtual Machine 虚拟机
- B-Tree B 树
- Pager 页缓存管理器
- OS Interface 操作系统接口
虚拟机将前端生成的字节码作为指令,可以对一个或多个索引执行操作,每个表或索引都存储在 B 树上(B 树:一种树状数据结构)。其实虚拟机本质上就是一堆判断字节码指令的switch
语句。
B 树由许多结点组成。每个结点的长度为一页。B 树可以通过向 pager 发出指令来执行 从磁盘检索页面或保存回磁盘
的操作。
pager通过接收指令读取或写入页,它负责以适当的偏移量在数据库文件中进行读取或写入。它还在内存中保留了最近访问页面的缓存,并决定何时将这些页面写回磁盘。
操作系统接口与上面提到的不在同一层。具体什么样的接口取决于为哪个操作系统的 SQLite 编译。在这个系列中,暂不支持跨平台。
本系列环境:
【操作系统】:Ubuntu 20.04 LTS
【语言】:C 语言
【编译器】: GCC 9.3.0
前置知识要求:
1. 会C语言,不要求精通,懂基本的 顺序结构、分支结构、循环结构 和 指针即可。
2. 对数据结构略有耳闻
3. 会 SQL 或 了解 SQLite
先整点好玩的~~
REPL
REPL,全称 Read Eval Print Loop:交互式解释器。
例如 Python 安装以后就自带 REPL ,在命令行下输入 Python
就可以启动
$ python
Python 3.8.5 (default, Aug 19 2020, 17:31:43)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> print("Hello World!")
Hello World!
>>>
动手实现
现在我们也自己实现一个
// MyREPL.c
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
int main() {
char command[100];
while (true) {
printf("BoiiDB > "); // 打印提示符
scanf("%s", command); // 接收输入
if(strcmp(command, ".q") == 0)