← [ BACK_TO_NOTES ]

数据库 Page 与 Buffer Pool

解释关系型数据库为什么按 Page 组织磁盘 I/O、Buffer Pool 如何缓存页面,以及这套存储模型为什么直接影响索引结构和查询性能。

#concept #growing #backend #database

[!info] related notes

数据库 Page 与 Buffer Pool

[!abstract] 一句话定义 关系型数据库通常以 Page(页)作为主要磁盘 I/O 与缓存单位,并由 Buffer Pool / Buffer Cache 管理内存中的 Page。查询性能常取决于需要访问多少 Page、访问模式是否连续,以及这些 Page 是否已在内存中。

为什么不是“按行读磁盘”

存储设备和文件系统适合按块传输数据;如果每读取一行都单独做随机 I/O,成本会非常高。

Disk / SSD
→ read fixed-size Page
→ Buffer Pool
→ executor accesses tuple / index entry

不同数据库页大小和布局不同,但“批量搬运、内存复用、减少随机 I/O”的目标相同。

一个 Page 里有什么

Page 通常包含:

  • Page Header;
  • Slot / Item Directory;
  • Row / Tuple 或 Index Entry;
  • Free Space;
  • Page-level Metadata;
  • 校验、日志位置或事务相关信息。

因此 Page 不是简单的“若干行拼在一起”,数据库还要维护空闲空间、可见性和更新位置。

Buffer Pool 做什么

读取 Page 时:

lookup page id in buffer pool
├─ hit  → pin / latch → read memory
└─ miss → choose victim → flush if dirty → read from disk

核心职责包括:

  • Page 查找与缓存;
  • Pin / Reference,避免使用中被淘汰;
  • Replacement Policy;
  • Dirty Page 管理;
  • Prefetch / Read-ahead;
  • 与 WAL / Checkpoint 协作。

Buffer Hit 不等于 Query 一定快

即使全部命中内存,仍可能因为扫描 Page 太多、锁竞争、CPU 计算、排序、Join 或内存复制而慢。

Buffer Miss 不等于每次都访问物理磁盘

操作系统 Page Cache、存储设备缓存和数据库自己的 Buffer Pool 可能共同参与。具体数据库是否绕过 OS Cache、如何 Flush,要按实现分析。

Dirty Page 与 WAL

修改行时,数据库通常先更新内存中的 Page,将其标记 Dirty,稍后再写回数据文件。

transaction changes page
→ WAL / Redo record becomes durable first
→ dirty page may flush later

这就是 Write-Ahead Logging 的核心约束:描述变更的日志必须先于对应 Data Page 持久化,崩溃后才能 Redo 未刷盘修改。

[!warning] COMMIT 不等于所有 Data Page 已写回 提交成功通常要求相关日志达到持久性条件;Dirty Page 可以由后台写回和 Checkpoint 稍后落盘。

随机 I/O 与顺序 I/O

  • Random I/O:跳到不同位置读取少量 Page;
  • Sequential Scan:连续读取大量 Page,更容易利用预读和存储吞吐。

因此命中表中大部分行时:

index scan + many random heap/table fetches

可能比顺序扫描全表更贵。优化器会根据选择性、相关性、缓存和成本参数做决策。

与 B+Tree 的关系

B+Tree 的 Node 通常映射到一个数据库 Page 或少量 Page:

fixed-size Page
→ internal node stores many keys + child pointers
→ high fan-out
→ low tree height
→ few Page accesses from root to leaf

所以数据库选择 B+Tree 的核心不是抽象复杂度 O(log n) 本身,而是降低外存 Page I/O。

Page Split、Fragmentation 与 Vacuum

Insert / Update 可能让 Page 空间不足:

  • B+Tree 发生 Page Split;
  • Heap / Table Page 留下 Dead Tuple 或 Fragment;
  • 数据库需要 Vacuum、Compaction、Rebuild 或后台清理。

这些行为会影响写放大、缓存命中、树高和磁盘占用。

Buffer Pool 与连接池不是一回事

Buffer Pool     → 缓存数据/索引 Page
Connection Pool → 复用数据库 Session / Connection

连接池满和 Buffer Cache Miss 都可能造成延迟,但排查路径完全不同。

观测与实验

可观察:

  • Buffer Hit Ratio;
  • Physical / Logical Reads;
  • Dirty / Checkpoint Write;
  • Page Read Latency;
  • Sequential vs Random Scan;
  • Table / Index Bloat;
  • Cache Eviction 与 Working Set。

[!example] 最小实验 构造一张较大表,分别执行高选择性索引查询和返回大部分行的查询,用 EXPLAIN ANALYZE 与 I/O 统计比较 Page 访问、回表和顺序扫描差异。

掌握标准

  • 能解释 Page 为什么是数据库 I/O 单位。
  • 能描述 Buffer Hit、Miss、Victim 和 Dirty Page。
  • 能说明 WAL 为什么要先于 Data Page 持久化。
  • 能解释为什么大范围查询可能放弃索引。
  • 能区分 Buffer Pool、OS Page Cache 和 Connection Pool。
创建于 2026/9/2 更新于 2026/9/4
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本