← 返回题目列表

B+ 树并发插入时页分裂怎么保证读写安全?

困难 第 25 / 25 题 更新于 2026/07/30
B+树并发控制页分裂latch

简化版

B+ 树并发插入时,页分裂会同时影响叶子页、父页和兄弟链表。数据库通常用页级 latch、锁耦合、分裂顺序和右兄弟指针等机制,保证读线程不会走到坏结构,写线程不会互相覆盖修改。

详细版

并发下的 B+ 树要区分两类保护:

  • 事务锁:保护数据逻辑并发,如行锁、间隙锁;
  • latch:保护内存页结构短时间不被并发破坏。

页分裂大致步骤:

  1. 对目标叶子页加写 latch;
  2. 分配新页,把部分记录搬过去;
  3. 设置新页和旧页的兄弟指针;
  4. 将分隔 key 插入父页;
  5. 必要时递归分裂父页;
  6. 释放 latch。

为了避免读线程在父页尚未更新时找不到新页,很多实现会维护右兄弟指针和 high key,让读者能从旧页向右追到正确页。具体实现依数据库而异,但核心目标是结构一致性和死锁规避。

完整版教学

一、为什么并发页分裂比单线程复杂

单线程里,页满了就分裂,再把分隔 key 插入父节点,过程可以一步步完成。并发场景中,读线程可能正在查这个范围,另一个写线程可能也想插入同一页。如果中间状态暴露出去,读可能漏数据,写可能覆盖指针,甚至树结构断裂。

B+ 树页分裂不仅改一个页,还会改叶子链表、父节点分隔 key,有时还会向上传播。并发控制必须保证这些局部变化对其他线程要么安全可见,要么能被纠正。

记忆钩子:事务锁管“谁能改哪条数据”,latch 管“页结构别在我手里散架”。

二、事务锁和 latch 有什么区别

事务锁面向用户数据语义,可能持有到事务提交。latch 面向内存结构保护,持有时间很短,通常只覆盖一次页读写或结构调整。把两者混淆,会很难理解数据库索引并发。

维度事务锁latch
保护对象行、范围、事务语义内存页、指针、页目录
持有时间可能到提交很短
目的隔离性结构一致性
例子行锁、间隙锁页读写 latch

B+ 树分裂主要需要 latch 保护结构,同时还要配合事务锁保证逻辑隔离。

三、分裂过程有哪些危险窗口

假设叶子页 P 满了,要分裂出新页 Q。如果先把部分记录搬到 Q,但还没更新父页,读者从根走下来仍会到 P。此时如果 P 不知道 Q 的存在,读者可能以为目标 key 不存在。若先更新父页但 Q 还没填好,读者可能进入未完成的新页。

因此实现需要规定安全顺序。例如先构造好 Q,再连接兄弟链,再发布父节点分隔信息。某些 B-link tree 设计会让旧页有 right link 和 high key,即使父节点暂时没更新,读者也能发现目标 key 超过当前页范围,然后向右追到新页。

P highKey=50, right=Q
查 key=60 到达 P
发现 60 > highKey,于是沿 right 到 Q

这种设计降低了父节点更新滞后的风险。

四、锁耦合和自顶向下保护

锁耦合指沿树向下走时,先拿到子页 latch,再释放父页 latch,保证移动过程中结构不会消失。插入时如果预判子页安全,不会分裂,可以早释放祖先 latch;如果子页可能分裂,可能要保留或重新获取父页写 latch。

不同数据库实现策略不同。有的采用自顶向下提前分裂,有的采用乐观下降,发现需要分裂再重试。核心目标都是减少 latch 持有范围,同时避免结构修改冲突。

五、右兄弟指针和 high key 的作用

叶子链表本来用于范围扫描,并发分裂时也能帮助查找纠偏。high key 表示当前页负责的最大 key 边界,right link 指向右兄弟。如果线程走到一个已经分裂但父节点还没完全同步的旧页,可以通过 high key 判断自己应该继续向右。

元信息作用
right link找到分裂后的右兄弟
high key判断目标 key 是否超出当前页
page latch保护页内结构修改
parent separator让后续查询从父页直接走对

这些机制组合起来,让 B+ 树在高并发写入下仍能保持可查找。

六、为什么要小心死锁和长时间 latch

如果线程 A 拿着叶子页 latch 等父页,线程 B 拿着父页 latch 等叶子页,就可能死锁。因此 B+ 树实现通常规定 latch 获取顺序,或在拿不到时释放并重试。latch 持有时间越短,系统吞吐越好。

页分裂还可能触发父页分裂,甚至一路到根。为了避免一次操作长时间锁住整条路径,工程实现会设计复杂的重试和安全节点判断。这也是数据库索引并发远比教材插入算法难的地方。

七、常见误区与追问

  • 误区:B+ 树并发只靠事务锁。 事务锁保护逻辑数据,页结构还需要 latch。
  • 追问:父页还没更新时读者怎么找到新页? 可通过 right link 和 high key 从旧页追到右兄弟。
  • 误区:页分裂只改叶子页。 它还会改兄弟指针和父节点分隔 key,可能向上传播。
  • 追问:为什么 latch 不能持有太久? 它阻塞结构访问,持有过久会严重影响并发吞吐。
  • 误区:所有数据库 B+ 树并发实现都一样。 具体协议不同,但目标都是结构一致、可恢复和高并发。

八、加强记忆

B+ 树并发分裂要同时照顾结构安全和查询可达。latch 短时间保护页结构,事务锁保护业务隔离;分裂要先让新页内容和兄弟关系安全,再发布父节点分隔信息;right link 和 high key 能处理父页更新滞后的窗口。面试中不用背某个数据库源码,能讲清这些危险窗口和保护手段就很扎实。