20250713 页的文件头中最小值和最大值的作用

20250713 页的文件头中最小值和最大值的作用

问题:页内是单链表,为什么记录了最小值,还要记录最大值,哪怕记录了最大值,也没法从最大值那反过来访问最大值的地址啊

在数据库存储引擎(如InnoDB)的页结构中,记录 最小记录(Infimum)最大记录(Supremum) 是出于 逻辑边界定义遍历优化 的需要,而非单纯为了双向访问。以下是详细解释:


1. 最小记录(Infimum)和最大记录(Supremum)的作用

(1) 逻辑边界标记

  • Infimum
    表示页中理论上的最小记录,比所有实际存储的记录都小(类似数学中的“负无穷”)。
  • Supremum
    表示页中理论上的最大记录,比所有实际存储的记录都大(类似“正无穷”)。

为什么需要它们?

  • 统一遍历逻辑:无论页内是否有数据,所有记录都位于 InfimumSupremum 之间,避免遍历时的边界条件判断。
  • 简化插入/删除操作:新记录插入时,可直接通过比较确定位置,无需特殊处理“第一条”或“最后一条”记录。

(2) 页内单向链表的访问优化

虽然页内记录是单向链表(通过 next_record 指针链接),但 InfimumSupremum 的存在使得:

  • 从头到尾遍历:从 Infimum 开始,沿 next_record 逐个访问,直到 Supremum 结束。
  • 范围查询优化
    例如查询 WHERE id > 100,数据库可以快速定位到第一个 id > 100 的记录,然后单向遍历到 Supremum,无需关心链表尾部。

2. 为什么不需要通过最大值反向访问?

  • 单向链表的设计初衷
    InnoDB的页内记录单向链表是为了高效顺序访问(如范围查询、全表扫描),而非随机反向遍历。
    • 若需要逆序访问,可通过索引的双向链表(如B+树叶子节点之间的 prev_page/next_page 指针)实现跨页遍历。
  • 空间效率
    每个记录增加反向指针会额外占用存储空间(尤其是行数多的页),而实际业务中逆序访问页内记录的需求极少。

3. 实际页结构示例

以下是InnoDB页内记录的简化布局(单向链表):

text

Infimum (最小记录) → Record1 → Record2 → ... → RecordN → Supremum (最大记录)
  • 所有操作均从 Infimum 开始
    • 插入新记录时,从 Infimum 出发找到正确位置。
    • 删除记录时,直接更新前驱记录的 next_record 指针。

4. 与B+树索引的关系

  • 页内单向链表:负责页内记录的顺序管理
  • B+树叶子节点双向链表:负责跨页遍历(如 ORDER BY id DESC 可通过 prev_page 指针逆序扫描)。

这种分工既节省了页内空间,又满足了全局查询需求。


5. 极端情况下的验证

假设不存储 Supremum

  • 插入最大值记录时:需特殊判断链表末尾,增加代码复杂度。
  • 范围查询到页末尾:需额外检查是否已遍历完所有记录。
    Supremum 的存在使得逻辑始终一致:

sql

-- 查询页内所有id > 100的记录
current = Infimum.next_record;
while (current != Supremum) {
    if (current.id > 100) return current;
    current = current.next_record;
}

总结

这种设计在 空间效率操作一致性 之间取得了最佳平衡。

设计选择 原因
记录Infimum 提供逻辑起点,统一插入/删除/遍历操作。
记录Supremum 提供逻辑终点,避免遍历时的边界判断。
不存储反向指针 逆序访问需求少,优先节省空间;跨页逆序通过B+树叶子节点双向链表实现。

问题2:可是b+树不是以页内记录最大最小值来分页的吗,如果统一用正负无穷来包围了最大最小值,那怎么分页呢

这里涉及到 B+树的分裂逻辑页内Infimum/Supremum的虚拟性 之间的区别。虽然页内用InfimumSupremum标记逻辑边界,但B+树的分页依然依赖实际数据的最大/最小值。以下是详细解释:


1. Infimum/Supremum 是页内的逻辑标记

  • 作用:仅为页内记录的遍历提供统一的起止点(类似链表的头尾哨兵节点),不参与B+树的分层决策

  • 虚拟性

    • InfimumSupremum是固定的伪记录(不存储实际数据)。

    • 例如:即使页内只有一条记录 (id=5),逻辑上仍表示为:

      text

      Infimum → (id=5) → Supremum
      

2. B+树的分页依赖实际数据的极值

B+树的分裂和层级划分基于页内实际存储数据的最大/最小值,而非Infimum/Supremum。具体逻辑如下:

(1) 非叶子节点的分页

  • 非叶子节点存储的是子节点的最小键值(或范围边界)。
    • 例如:某非叶子节点条目为 [10, 20, 30],表示:
      • 第一个子节点中的所有数据 < 10
      • 第二个子节点中的数据 >= 10 且 < 20
      • 第三个子节点中的数据 >= 20 且 < 30

(2) 叶子节点的分页

  • 叶子节点之间通过双向链表连接,且每个叶子节点存储实际数据
  • 分裂条件:当页内实际数据超过大小时(如16KB),按以下步骤分裂:
    1. 找到页内实际数据的中间值(如原页有数据 [5,8,10,15,20],中间值为 10)。
    2. 新页包含 [10,15,20],原页保留 [5,8]
    3. 更新父节点:将新页的最小值(10)插入父节点,作为分界键。

(3) 关键区别

对比项 Infimum/Supremum B+树分页依据
用途 页内遍历的边界哨兵 树形结构的层级划分
是否存储数据 否(虚拟记录) 是(实际数据的最小/最大值)
影响范围 仅限当前页 全局索引结构

3. 示例:B+树分裂与Infimum/Supremum无关

假设一个叶子页已满,实际数据为 [3,5,8,10,15](逻辑结构为 Infimum→3→5→8→10→15→Supremum):

  1. 分裂时
    • 选择中间值(如 8),新页存储 [8,10,15],原页保留 [3,5]
    • 父节点新增键值 8(新页的最小实际数据),而非 Supremum
  2. 分裂后
    • 新页的逻辑结构仍是 Infimum→8→10→15→Supremum
    • 原页的逻辑结构变为 Infimum→3→5→Supremum

Infimum/Supremum始终存在,但分裂完全依赖实际数据


4. 为什么设计如此?

  • 职责分离
    • Infimum/Supremum 解决页内操作一致性问题(如插入/删除无需判空)。
    • B+树的分页解决数据分布与查询效率问题。
  • 性能优化
    • 实际数据的极值可直接用于索引定位,而虚拟记录无实际查询意义。

5. 总结

  • Infimum/Supremum 是页内的“脚手架”,仅用于简化页内链表操作。
  • B+树的分页 基于页中实际数据的物理极值,二者互不干扰。
  • 类比
    • Infimum/Supremum 类似书页的“页眉/页脚”,而B+树的分页是图书馆的“书架分类规则”——书架不会因为页眉写了个“Chapter 1”就把书分成两半。

这种设计确保了高效的单页操作与全局索引结构的解耦!

6. 结论

  • Infimum/Supremum 解决页内操作一致性问题(如插入/删除无需判空)。
  • B+树的分页解决数据分布与查询效率问题。

注:学习MySQL时的笔记,笔记来源是尚硅谷的课件

posted @ 2025-07-13 21:04  kokoasann  阅读(12)  评论(0)    收藏  举报