把同样的500万行数据塞进PostgreSQL,只换一个存储引擎,然后故意把数据库弄崩——结果会差多少?
这不是一个纯理论问题。数据库引擎是数据库里负责把"保存这一行"翻译成磁盘上字节、再翻译回来的那部分。它决定了你的读写速度、崩溃后能不能恢复、以及磁盘空间被吃掉多少。
![]()
没有哪个引擎是全能冠军。行存储适合事务,LSM树适合高频写入,列存储适合分析,内存引擎适合追求速度的场景。而PostgreSQL允许你按表选择引擎,语法就是CREATE TABLE ... USING 。
一个天真的引擎会怎么死
要理解引擎为什么长成现在这样,最简单的办法是先造一个最直白的版本,然后看它怎么崩。
最直白的做法:每一行就是文本文件里的一行。写入20万行用户数据,很快就会发现三个问题。
第一,读取成本取决于你要哪一行。找第N行意味着数N个换行符。第0行耗时0.25毫秒,第199999行耗时17.6毫秒——在一个不到5MB的文件上,慢了70倍。
第二,一行变长会覆盖邻居。唯一安全的修法是把它之后的所有内容重写一遍。改了40个字节,却要写4.6MB,写放大达到121667倍。
第三,崩溃会造出一行从未存在过的数据。把42,alice,1000替换成42,bob,2000的过程中断电,你会得到42,bobce,1000。它能正常解析,所以没有任何警告。
真实引擎的四个解法
真实引擎用四个思路解决这些问题。
思路一:页。把每个文件切成固定大小的块,称为页。PostgreSQL用8KB。找第5000个块变成简单的算术(5000×8192),每次读取成本相同。页成为磁盘I/O、缓存和崩溃恢复的基本单位。
思路二:槽页。在每个页内部,前端有一个小的槽数组,指向存储在尾部的行。两个区域相向生长。一行的地址是(页,槽),不是字节偏移。所以引擎可以在页内移动行来回收空间,而所有指向(5,3)的索引项依然有效。
思路三:校验和与预写日志。校验和检测损坏:每个页存储自身字节的校验和,所以写了一半的页会验证失败,而不是返回42,bobce,1000。预写日志(WAL)修复损坏:在改动页之前,引擎先把变更描述追加到顺序日志并刷盘。如果数据库在第3步之前崩溃,恢复过程会重放日志。
思路四:MVCC。不覆盖行,而是写入新版本,并给每个版本打上创建它的事务(xmin)和替换它的事务(xmax)标记。每个事务从快照读取,所以一份长报告持续看到旧余额,同时一个更新在旁边提交。读从不阻塞写。代价是旧版本会堆积,必须清理——这就是PostgreSQL的VACUUM做的事。
四种引擎,四种取舍
上面四个思路描述的是PostgreSQL的默认引擎。其他引擎做出不同的取舍,取决于它们优化什么。
行存储(B树+页):整行放在一起存在页里,原地更新,用B树索引找到它们。经典设计。擅长事务、点查询、频繁更新(OLTP)。弱点是跨数十亿行扫描少数几列,因为它无论如何都要读整行。例子:PostgreSQL heap、MySQL InnoDB、SQLite、Oracle、SQL Server。
日志结构合并树(LSM):从不原地更新。写入先进内存缓冲区(外加一个日志保证安全)。缓冲区满了就刷到磁盘成为一个不可变的排序文件,后台压缩随时间合并这些文件。擅长极高的写入和摄入速率,因为每次磁盘写入都是顺序的。弱点是读取可能要检查多个文件(布隆过滤器有帮助),压缩会占用后台CPU和I/O。例子:RocksDB、LevelDB、Cassandra、ScyllaDB、MyRocks、CockroachDB的Pebble。
列存储:每一列单独存储并压缩。一个只需要12列中2列的查询,只读那2列。擅长聚合、仪表盘、大表扫描这类分析场景(OLAP),磁盘占用小得多。弱点是更新或删除单行,以及一次取一整行。例子:ClickHouse、DuckDB、Snowflake、BigQuery、Parquet文件、PostgreSQL的Citus/Hydra列存。
内存存储:所有东西放RAM。持久性来自快照和追加日志,或者干脆放弃持久性。擅长缓存、会话、排行榜和队列这类微秒级延迟场景。弱点是RAM昂贵,以及持久性上的妥协。
选哪个引擎,取决于你的负载是读多还是写多、是事务还是分析、能不能接受崩溃后丢数据。没有标准答案,只有取舍。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
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.