知识全景图/ 软件工程与系统/ 如何设计一个数据库

如何设计一个数据库

按 MiniDB 失败顺序设计 DBMS:存得住、找得到、查得快、改得对、崩了能恢复。

目标:不是给业务系统建表,而是设计数据库软件本身。第一版只支持几条 SQL,但每一步都要能解释为什么需要这个内部机制。
一、MiniDB 最小目标
CREATE TABLE users(id int, name text); INSERT INTO users VALUES (1, 'alice'); SELECT * FROM users WHERE id = 1; UPDATE users SET name = 'bob' WHERE id = 1; COMMIT; -- kill process, restart SELECT * FROM users WHERE id = 1; -- still exists
二、七页主线
顺序页面解决的失败
总页如何设计一个数据库先确定 MiniDB 要拆成哪些核心部件。
第一页如何设计存储引擎内存会丢,追加文件不好更新,所以要页、记录地址、Buffer Pool。
第二页如何设计 B+Tree 索引全表扫描太慢,所以要从 key 快速找到 RID。
第三页如何设计 SQL 执行器SQL 字符串不能直接跑,要变成扫描、过滤、投影、更新算子。
第四页如何设计查询优化器能执行不等于会选好计划,需要选择索引、Join 顺序和代价模型。
第五页如何设计事务系统并发写会覆盖,失败会半成功,所以要事务状态、锁、隔离和回滚。
第六页如何设计 WAL 和崩溃恢复commit 后宕机不能丢,未提交落盘不能留,所以要日志、Redo、Undo。
第七页如何设计 MVCC锁能保正确,但读写互相卡,所以要版本链、快照和可见性规则。
三、一个数据库从失败中长出来
失败长出的机制
内存 Map 重启就丢。文件、页、记录格式。
文件能存,但不知道一条记录在哪。page_id、slot_id、RID。
每次读磁盘太慢。Buffer Pool。
按 id 查要扫全表。B+Tree 索引。
SQL 只是字符串。Parser、Binder、Executor。
多个计划都能跑,但快慢差很多。Optimizer。
两个事务同时写坏数据。事务管理、锁、隔离。
崩溃后不知道保留谁、撤销谁。WAL、Redo、Undo、Checkpoint。
读写互相阻塞。MVCC。
一句话:设计一个数据库,就是设计“行怎样落盘、记录怎样定位、查询怎样执行和优化、并发怎样正确、崩溃怎样恢复、读写怎样共存”。