从 SQL 查询到存储读取
SQL 执行把结果需求变成计划、页请求和返回行。索引缩小要访问的页,数据库缓冲池决定访问是否需要向存储层读页。本课同一查询首次读三页得到 Mira,第二次仍得到 Mira,却不再读取存储。
请求页面和从存储读取页面是两件事。同页可以请求两次、只读一次。缓冲池在内存保留页副本,复用的是页面,不是每条 SQL 的现成答案。
SQL 怎样到达存储层
查询为 SELECT name FROM users WHERE id = 42;。解析确定投影 name、关系 users、条件 id=42,绑定再对照表模式解析名称。本课规划器直接给出 Index Scan,以观察页依赖。真实规划器会比较估算成本,小表可能更适合顺序扫描。阶段边界可参看 PostgreSQL 查询路径。
二级索引保存 id 及行定位信息,即堆页地址和页内槽位,不保存 name。找到 42 只知道下一步去哪读,还没有请求的名字;执行器必须读取堆元组再投影 name。这对应二级索引与堆存储的分离。
每次访问页,包括索引根和叶,都先经过缓冲池。命中就使用内存副本;未命中才请求存储,并把返回页放入空帧。源页仍留在存储中,执行器等页可用后才能查看内容。
画面下层称为 Storage。数据库读请求不证明物理磁盘或 SSD 被访问,操作系统缓存也可能满足它。这里统计的是数据库缓冲层以下的模拟页获取,不是实测设备 I/O;区别见 PostgreSQL I/O 统计说明。
SQL 到存储读取逐步演示
默认连续执行两次。四帧缓冲池起初为空,准备一次计划,执行后保留页面,再执行相同计划,数据不变。
| 堆页 | 槽位 1 | 槽位 2 |
|---|---|---|
| H0 | 7 · Ada | 63 · Gus |
| H1 | 12 · Bo | 40 · Eli |
| H2 | 23 · Cy | 91 · Hana |
| H3 | 35 · Dee | 42 · Mira |
根 R 的分隔键为 40,<40 去 L0,≥40 去 L1。L1 保存 40、42、63、91 及堆定位信息。堆行的物理顺序不等于索引顺序。
- 解析并绑定
SELECT name FROM users WHERE id = 42;。Index Scan 需要 id 索引,name 不在载荷中,所以还需堆读取。 - 请求根 R,空缓冲未命中,存储返回整页并保留在帧中,读计数为 1。42 与 40 比较后选 L1。
- 请求 L1,也未命中。第二次读页后找到
42 → H3 / slot 2,执行器此时仍不知道 name。 - 请求 H3,第三次未命中。整页带来
35 · Dee和42 · Mira,定位到槽 2,投影返回 Mira。本轮计数为请求 3、命中 0、读取 3。 - 清空结果与单次执行计数,保留 R、L1、H3,再执行。三个请求都命中;仍要比较根、查叶、跟随定位、投影元组,返回 Mira。计数为请求 3、命中 3、读取 0。
- 比较两次记录:查询、计划、结果相同,变化的是驻留页。合计六次请求、三次存储读取,第二次自己的读取数为零。
热缓存为何能省读取
本模型一次执行完成时:page requests = buffer hits + storage reads。它数请求,不只数不同页面。未命中还在等待时,等式未必暂时成立。读取在存储传输节拍只计一次,安装缓冲帧不重复计数。
| 场景与目标 | 页请求 | 命中 | 存储读取 | 结果 |
|---|---|---|---|---|
| 连续两次,42,首次 | 3 | 0 | 3 | Mira |
| 连续两次,42,重复 | 3 | 3 | 0 | Mira |
| 预热缓冲,42 | 3 | 3 | 0 | Mira |
| 无索引,42 | 4 | 0 | 4 | Mira |
| 缺失键,43 | 2 | 0 | 2 | 零行 |
预热缓冲把驻留页声明为初始状态,之前的加载成本不计入本次记录。若重复前清空页面,又会读取三次;SQL 文本相同不保证页还在。
索引改变访问路径,缓存改变满足访问的成本。更高索引树每层都要访问一页,匹配后还需堆页;顺序扫描则访问全部堆页。哪些访问落到存储取决于驻留状态。页数不包含全部 CPU、局部性和延迟因素,少读几页不是普遍更快的证明,详见索引课程。
边界情况
- 43 属于 L1 范围却不存在,读 R、L1 后就能确认,无定位信息,不请求堆页。零行也是成功执行。
- 分隔键相等的 40 走右侧,因为规则为
<40、≥40。7、91 可检验首尾键。 - 无索引时扫全部四页,即使目标 7 在 H0 先命中,也继续到 H3。
- 热缓冲查缺失键,只需根和候选叶驻留,两次命中、零行、零存储读。
- 当前最多需要四驻留页,不发生淘汰。更大工作集可能失去热缓存收益,策略见页面置换。
- UI 接受整数 0–99,是显示限制,不是 SQL 限制。数据只有八行,其他合法目标返回零行。
常见错误
- 把缓冲未命中当“行不存在”。它只说明页不在内存,读页后才能判断键。
- 把
H3 / slot 2当投影值。它是位置,覆盖索引可以携带 name,但当前索引没有。 - 每行算一次读取。传输单位是整页,H3 的两行一起到达。
- 认为零存储读就是零工作。重复仍执行页请求、查找和元组处理。
- 将计数称为物理设备 I/O。本模型止于存储接口,设备访问、系统缓存和耗时需额外测量。
模型范围
本课用小型二级 B+ 树、非聚簇堆、固定可见行、一个相等条件、四个缓冲帧。省略目录和规划 I/O、索引元页、MVCC 可见性变化、锁、并发查询、淘汰、写入、WAL、预取、系统与设备缓存及真实成本估算。页容量、槽位和计数属于当前样例,实际数据库可能执行更多工作或选择别的计划。