<!-- title: 一次讲透Postgres：8KB页面里的存储真相 -->
<!-- domain: programming -->
<!-- video: https://www.youtube.com/watch?v=q9jixKv4h2I -->

# 一次讲透Postgres：8KB页面里的存储真相

## 导语：为什么一个白板课能两周拿下近10万播放

如果你写过后端代码，Postgres 大概率在你的技术栈里。但一个尴尬的事实是：绝大多数工程师和数据库的关系，停留在“会用 SQL”的层面——至于一行数据INSERT进去之后物理上发生了什么、为什么大表UPDATE会让磁盘暴涨、为什么一个忘了提交的事务能拖垮整库——全靠猜。

2026年8月13日，后端工程领域知名教育者 Hussein Nasser 上架了一期视频：**《you won't forget how postgres works after this》**（看完这期你就忘不掉 Postgres 的工作原理了）。标题很狂，但数据给了底气：发布仅两周播放量约9.7万（对垂类数据库内核内容来说，这个速度相当快），视频时长26分57秒，是他"Intermediate and Advanced Backend Engineering Course"系列的白板课第一部分。

这期视频的价值在于：**它不讲语法、不讲调优参数，而是回到存储的最小物理单元——Page（页）、Heap（堆）、Tuple（元组），把数据库从“黑盒软件”还原成“有空间结构的数据仓库”**。你一旦在脑子里建立起那张“8KB页面”的图，很多以前死记硬背的结论（比如“Postgres 更新就是追加新行”）会瞬间变成“显然如此”。

更难得的是，Hussein 是白板教学——不念幻灯片，而是当着你的面把结构画出来。这种教学法本身就值得所有技术内容创作者学习。下面我们逐层拆解。

## 视频背景卡片

| 项目 | 内容 |
|------|------|
| 视频标题 | you won't forget how postgres works after this |
| 频道 | Hussein Nasser（@hnasr，后端工程领域头部技术频道） |
| 发布日期 | 2026年8月13日 |
| 时长 | 26分57秒 |
| 播放量 | 约9.7万（发布两周内，据YouTube搜索页数据） |
| 内容形式 | 白板课（Whiteboard lesson），中级/高级后端工程课程系列 Part 1 |
| 核心主题 | PostgreSQL 存储架构基础：pages、heaps、tuples 及其在数据操作、存储与事务管理中的交互 |

## 核心内容拆解

### 1. 一切从 Page 开始：8KB 是 Postgres 世界的“原子”

视频的主线，是把 Postgres 的存储世界还原成三层结构：**Database → Heap（表文件）→ Page（页）→ Tuple（元组）**。

你的一张表，在磁盘上并不是 Excel 那样的二维表格，而是若干个 8KB 大小的 Page 串成的集合。Page 是 Postgres 读写磁盘的**最小单位**——哪怕你只想改一行 100 字节的数据，Postgres 也要把这一行所在的整个 8KB 页面读进内存，改完再写回去。

**我的延伸分析**：为什么偏偏是 8KB？这与文件系统块的典型大小（4KB）有关——8KB 是文件系统块的整数倍，避免了“读一个逻辑页要碰两次磁盘块”的碎片问题；同时它又足够小，不至于让一次单行修改就搬运几MB的垃圾数据。这个数字是 Postgres 编译期固定常量（BLCKSZ），默认不能在线修改。理解“Page 是 IO 的原子单位”后，你会明白一个反直觉的结论：**行再小，写放大也是 8KB 起**。这也是为什么超宽表（几百列）和频繁单行更新在小机器上是灾难。

### 2. Heap（堆）：你的“表”其实是一堆无序的页面

视频第二个关键概念是 Heap。Postgres 的表在术语里叫 "heap table"——堆表。这个名字本身就在提醒你：**数据在物理上是“堆”进去的，不保证任何顺序**。

页面用链表式的结构串联，新行写入时通常追加到还有空间的页面里。表里没有“第几行”的概念——每一行（Tuple）真正的身份证是 **CTID**，即 `(页号, 页内偏移)` 的物理坐标。

**我的延伸分析**：这一点直接解释了两个高频面试题和两个生产事故：
- **为什么 `ORDER BY` 需要排序步骤？** 因为堆里数据本来就是乱的；
- **为什么没有索引的 `WHERE` 查询是全表扫描？** 因为数据库只能从第 0 页开始一页页翻，像在没有目录的书里找一句话；
- **CTID 为什么不能当主键？** 因为下一节要讲的 MVCC 机制会让行的物理位置随时变化——VACUUM 收缩页面后 CTID 就变了。

视频用白板画出这个“页串”的瞬间，比读十遍文档都直观——这正是标题里 "you won't forget" 的底气所在。

### 3. Tuple 与行头：MVCC 的物理机关藏在每行数据里

这是本视频最有“含金量”的部分。每个 Tuple 不只是你的业务数据，前面还挂着一个**行头（Tuple Header）**，里面藏着几个对用户不可见的字段——最核心的是 **xmin**（创建该行版本的事务ID）和 **xmax**（删除/作废该行版本的事务ID）。

这套设计是 Postgres **MVCC（多版本并发控制）**的物理基础：**Postgres 的 UPDATE 从不原地修改数据，而是写入一个新版本的 Tuple，再把旧版本的 xmax 打上标记；DELETE 也只是打标记，不立刻释放空间。**

**我的延伸分析**：这个设计是一次深刻的取舍——
- **换来的**：读写互不阻塞。读旧版本的快照，写新版本，二者并行，这就是 Postgres 高并发的秘密；
- **付出的**：旧版本 Tuple（Dead Tuple，死元组）不会自动消失，必须靠 **VACUUM** 进程事后清扫。清扫不及时，表就会“膨胀”（Table Bloat）——表文件里装着大量已死但还占着 8KB 页面空间的数据。

一句话记住它：**在 Postgres 里，UPDATE = INSERT + 给旧数据贴封条，VACUUM 是清道夫。** 这一条如果只能记住一件事，就是它。

### 4. 用这套结构反推三大“日常玄学”

视频的高明之处在于：它不是孤立地讲结构，而是让结构**解释现象**。理解 Page/Heap/Tuple 之后，以下三个工程界的“玄学”瞬间变成必然（此节为我的延伸映射，逻辑与视频主线一致）：

**玄学一：为什么长事务是数据库大敌？**
因为 VACUUM 不能清理“仍可能被某个事务看见”的死元组。一个开了三天没提交的事务，等于让全库的死元组堆积三天——磁盘暴涨、查询变慢，而罪魁祸首可能只是一个忘了 commit 的调试会话。

**玄学二：为什么 `COUNT(*)` 在 Postgres 里慢？**
因为“一行是否存在”取决于 MVCC 可见性判断——每个后端进程要根据自己的事务快照逐行判断可见性，没有任何缓存能告诉你一个全局精确的行数。这是 MVCC 的代价，不是优化不够。

**玄学三：为什么删了数据磁盘不变小？**
因为 DELETE 只是打标记，页面里的空间被标记为可复用，但文件本身不收缩（除非用 VACUUM FULL 这种锁表的重型操作）。

### 5. 行太大怎么办：TOAST 的“压缩+外置”策略（延伸）

视频系列围绕页面与元组展开，这里补充一个与之直接相关的机制——**TOAST**（The Oversized-Attribute Storage Technique）。Postgres 页面是 8KB，而单个 Tuple 理论上必须能装进一个页面。那 text、jsonb 这种可能几MB的大字段怎么办？

Postgres 的策略是两步：先**压缩**，压不下再**行外存储**——把大字段切到一张看不见的关联表（TOAST 表）里，主行里只留一个指针。大字段独立成链，读取时按需取出，还能利用页面不装大字段这一点让数据页更“密”。

**实战意义**：当你的 jsonb 字段动辄几百KB时，每一次 SELECT * 都可能触发 TOAST 解压与重组——这就是“宽 JSONB 表查询慢”的底层原因。

### 6. WAL：改页面之前，先写日记（延伸）

页面结构讲清楚了，还差最后一块拼图：崩溃了怎么办？Postgres 的答案是 **WAL（Write-Ahead Log，预写日志）**——任何对页面的修改，在落盘之前必须先把“我改了什么”写入 WAL 并持久化。

崩溃恢复时，数据库从上一次检查点（Checkpoint）开始重放 WAL，把页面“重做”到一致状态。它和 Page/Tuple 的关系是：**WAL 记录的是对页面的物理级变更，页面是变更的承受者，检查点是两者同步的里程碑。** Hussein 频道更早的一期《PostgreSQL Internal Architecture Explained》（21.2万播放）把 WAL、Checkpointer、Autovacuum 等后台进程体系讲得更系统，适合作为本片的“续集”。

### 7. 白板教学法：为什么“画出来”就是忘不掉

最后值得单独说的是这期视频的**形式**本身。Hussein 全程白板手绘，没有一页 PPT。当“页面→元组→行头”的空间关系被画在同一块板面上，你记住的不是知识点，而是一张**空间地图**——这正是认知科学里“空间记忆优于线性文本记忆”的经典应用。

对技术内容创作者的启示：讲底层机制，最高效的载体不是动画炫技，而是**一块板、一支笔、一条从存储介质到内存的完整推理链**。这也是这条视频两周近10万播放的传播学解释：它提供的不是信息，而是心智模型。

## 知识结构图

```text
flowchart TD
    A[Postgres 存储世界] --> B[Heap 堆表文件]
    B --> C[Page 页 8KB / IO最小单位]
    C --> D[Tuple 元组 = 行头 + 业务数据]
    D --> D1[ xmin 创建事务ID ]
    D --> D2[ xmax 作废事务ID ]
    D1 & D2 --> E[MVCC 多版本并发控制]
    E --> F[UPDATE = 新版本 + 旧版打标记]
    F --> G[Dead Tuple 死元组]
    G --> H[VACUUM 清道夫]
    H --> H1[堆积 → 表膨胀]
    C --> I[行超8KB → TOAST 行外存储]
    C --> J[页面修改先写 WAL 预写日志]
    J --> K[Checkpoint 检查点 / 崩溃恢复]
    E --> L[可见性判断 → COUNT(*) 慢 / 长事务阻塞清理]
```

## 实战启示：看完这26分钟，你该改掉哪些习惯

**1. 把“长事务监控”提到最高优先级。** 立刻检查你的生产库：`SELECT pid, now()-xact_start AS dur, query FROM pg_stat_activity WHERE state <> 'idle' ORDER BY dur DESC;` 任何超过几分钟的未结束事务都值得警惕。连接池配置里给 `idle_in_transaction_session_timeout` 设一个上限，是成本最低的保险。

**2. 学会用死元组比例判断表健康度。** `SELECT relname, n_dead_tup, n_live_tup FROM pg_stat_user_tables;` 当 `n_dead_tup / n_live_tup` 明显偏高（比如超过20%），说明 autovacuum 跟不上更新频率——高频 UPDATE 的表应单独调激进的 autovacuum 参数，而不是用全局默认值。

**3. 批量更新学会“分批提交”。** 一次 UPDATE 一千万行 = 一千万个死元组 + 一个巨大的长事务。改成每批5000行、批间提交，vacuum 才有机会跟上。

**4. 宽 JSONB 表慎用 SELECT *。** 明白 TOAST 机制后你会知道， SELECT * 可能把几个MB的 TOAST 数据拖出来。按需取列，或把大 JSON 拆成独立冷表。

**5. 面试与学习的降维打击。** 当面试官问“为什么 Postgres 不需要 VACUUM 的 MySQL（InnoDB）有 undo log？”，你能从“行头里的 xmin/xmax + 堆表不原地更新”一路讲到“回滚段 vs 死元组清理”的架构分野——这种从物理结构出发的回答，比背八股文高一个段位。

## 延伸学习路径

1. **Hussein Nasser —《PostgreSQL Internal Architecture Explained》**（21.2万播放，15章节）：本片的“全景续集”，覆盖 Postmaster、Backend Processes、Shared Buffers、WAL、Autovacuum 等完整进程与内存架构。
2. **The Coding Gopher —《99% of Developers Don't Get PostgreSQL》**（31.5万播放，12分钟）：快节奏版内核入门，ACID、MVCC、WAL、TOAST 一网打尽，适合先看它再回来看白板课。
3. **Denis Magda —《PostgreSQL Internals in Action: MVCC》**（16分钟）：用 pageinspect 扩展亲手解剖真实页面，把本文的“行头/xmin/xmax”真正看进眼睛里。
4. **Postgres 官方文档 Chapter 65 "Database Physical Storage"**：页结构的权威定义（PageHeader、ItemId、空闲空间_map），所有视频内容的最终依据。
5. **Postgres.FM 播客 / PostgresTV**：Hussein 频道搜索结果中可见的社区常客资源，每周讨论真实生产问题，是内核知识“保鲜”的最佳渠道。

## 一句话总结

**当你真正看见“一行数据 = 8KB页面里带着 xmin/xmax 出生证的一条记录”，Postgres 的所有怪脾气——膨胀、慢 COUNT、长事务之祸——都不再是需要背的结论，而是推一遍就懂的必然。**

## 参考来源

1. [you won't forget how postgres works after this — Hussein Nasser](https://www.youtube.com/watch?v=q9jixKv4h2I) — 本文分析的核心视频，2026-08-13发布，时长26:57
2. [Hussein Nasser 频道 PostgreSQL 内部架构系列（PostgreSQL Internal Architecture Explained，21.2万播放）](https://www.youtube.com/watch?v=Q56kljmIN14) — 补充进程与内存架构全景
3. [The Coding Gopher — 99% of Developers Don't Get PostgreSQL（31.5万播放）](https://www.youtube.com/watch?v=P8rrhZTPEAQ) — 同主题快节奏补充视角
4. [Denis Magda — PostgreSQL Internals in Action: MVCC](https://www.youtube.com/watch?v=MIlhEJ5bi-o) — pageinspect 实操参考（据YouTube搜索结果中的频道内容整理）
5. [PostgreSQL 官方文档：Database Physical Storage](https://www.postgresql.org/docs/current/storage.html) — 页与堆存储的权威定义

---
> 本文由「51学通信」技术团队出品。51学通信由通信行业18年老兵**爱卫生**（微信ID: gprshome201101）维护，聚焦5G/6G核心网、3GPP标准解读、通信前沿技术深度分析。
> 出版作品有《5G核心网原理与实践》《IMS原理与实践》等4本通信专业书籍。知识星球「51学通信」提供深度技术答疑和行业洞察。

> [!tip] 51学通信知识星球
> **星主：爱卫生**（微信：gprshome201101）——公众号「51学通信」创办者，19 年通信行业运维与讲师经验，著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书（各大电商平台有售）。
> **星球定位**：深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域，主打运维岗位与信令分析。
> **当前规模**：5200 篇主题 / 990 个回答，198 元/年。
> **加入福利**：加入星球后请加爱卫生微信，拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题，另有群内分享。
> **AI 加持**：51学通信知识星球已作为 skill 接入 WorkBuddy，使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例，做总结、找文档和 PPT 等场景全覆盖。

![51学通信知识星球海报-扫码加入](https://wiki.500nian.com/images/zhixingqiu_qrcode.png)
