首页 › programming › 一次讲透Postgres:8KB页面里的存储真相

一次讲透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万播放的传播学解释:它提供的不是信息,而是心智模型。

知识结构图

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 — 本文分析的核心视频,2026-08-13发布,时长26:57
  2. Hussein Nasser 频道 PostgreSQL 内部架构系列(PostgreSQL Internal Architecture Explained,21.2万播放) — 补充进程与内存架构全景
  3. The Coding Gopher — 99% of Developers Don't Get PostgreSQL(31.5万播放) — 同主题快节奏补充视角
  4. Denis Magda — PostgreSQL Internals in Action: MVCC — pageinspect 实操参考(据YouTube搜索结果中的频道内容整理)
  5. PostgreSQL 官方文档:Database Physical Storage — 页与堆存储的权威定义

本文由「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学通信知识星球海报-扫码加入