知识卡片
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树的一个优点
是每个键只存在于索引中的一个位置……这些锁可以直接连接到树。