知识卡片

B树与LSM树的核心权衡写放大读性能可预测性与事务锁

结构图卡

内容

[[LSM树用内存表加WAL兼顾写入速度与崩溃安全]]和[[B树用固定大小页面树保证O-logn深度 并靠WAL防崩溃损坏]]的经验法则是:LSM树写入更快,B树读取更快,但这只是起点,真正 的权衡藏在细节里。写放大是理解两者代价的关键概念——”数据库生命周期中每次写入用户 数据,最终导致对磁盘执行多次实际写入”。B树至少要写两次每一份数据:一次写WAL,一次 写树页面本身(即使页面里只有几个字节变了,也要整页重写,某些引擎甚至覆盖同一页面 两次以防电源故障导致页面部分更新)。LSM树因为反复压缩合并SSTable,同样会重写数据, 但通常写放大更低、且是把随机写转成顺序写紧凑的SSTable文件(不必覆盖树中多个分散 页面),因此往往能支持比B树更高的写入吞吐量,在磁盘旋转的机械硬盘上这个差异尤其 明显;LSM树也因为不是面向页面、且定期重写去除碎片,磁盘占用通常比B树更紧凑(B树 的页面分裂会留下未充分利用的空间)。代价方面:LSM树的压缩过程会和正在进行的读写 竞争有限的磁盘带宽,如果压缩跟不上写入速率,未合并段会越堆越多、读取要检查更多 段而变慢,直到磁盘空间耗尽——而且多数基于SSTable的引擎不会主动限制写入速率,需要 人工监控;这导致LSM树查询响应时间在高百分位点上有时会明显不可预测,不如B树的行为 稳定。此外B树有个结构性优势:每个键只存在于索引里的一处位置,而日志结构引擎可能 在不同段里保留同一个键的多个副本,这让B树更适合需要基于键范围加锁来实现强事务 隔离的数据库——锁可以直接挂在B树上,这一点将在事务章节详述。

结构图

flowchart LR
    A[LSM树] --> A1[写放大通常更低, 顺序写紧凑SSTable]
    A --> A2[写吞吐量通常更高]
    A --> A3[压缩与读写竞争磁盘带宽, 高百分位延迟不可预测]
    A --> A4[同一键可能有多副本分散多段]
    B[B树] --> B1[每份数据至少写两次: WAL+页面本身]
    B --> B2[读取性能更可预测]
    B --> B3[每个键只存在索引一处位置]
    B3 --> B4[更适合基于键范围加锁的事务隔离]

参考来源

- 位置:《数据密集型应用系统设计》第三章《存储与检索》"比较B树和LSM树"(源文件: _epub-src/ch3_split_001.html) - 结论依据:原文定义写放大概念,说明B树至少写两次数据而LSM树通常写放大更低且是 顺序写、因此写吞吐量更高,同时指出LSM树压缩会与读写竞争磁盘带宽导致高百分位 延迟不可预测,以及B树每个键只存在索引一处、更适合基于键范围加锁的事务隔离, 直接支撑本卡片的权衡结构梳理。 - 原始内容:根据经验,通常LSM树的写入速度更快,而B树的读取速度更快……这种影响 ……被称为写放大……LSM树通常能够比B树支持更高的写入吞吐量……对日志结构化存储 引擎的查询响应时间有时会相当长,而B树的行为则相对更具可预测性……B树的一个优点 是每个键只存在于索引中的一个位置……这些锁可以直接连接到树。