PostgreSQL 核心机制 · 深潜

从一条规则读懂 PostgreSQL

基于 PostgreSQL 18(2025-09 发布,最新小版本 18.4)。阅读时长约半天(深潜)。SQL 与 EXPLAIN 示例基于 PG 18 语法,未在本机逐条执行(已就地标注)。

这份教程不按 SQL 语法的顺序铺开,而是围绕一条贯穿全篇的机制主线展开:PostgreSQL 的写操作从不原地修改数据。存储、事务、回收、索引、规划器,全部挂在这条主线上。读完之后,PG 的运维直觉对你不再是一堆要背的规则,而是一条能推导的因果链。

§适合谁 / 不适合谁

这份教程为你写,如果你符合以下三条:

  • 能写多表 JOIN、建过 B-tree 索引、用过事务,但说不清 PostgreSQL 为什么需要 VACUUM。
  • 用 psql 或某个 ORM 连过 PG,知道增删改查怎么写,但没认真读过一次执行计划。
  • 有另一种关系库(多半是 MySQL)的直觉,想知道 PG 哪里不一样、为什么不一样。

这份教程不适合你,请看更合适的资源:

§读完之后你能做到什么

这份教程给你的核心能力

看到 PG 的任何"怪行为"——表越删越大、count(*) 慢、加了索引反而写更慢、半夜 autovacuum 把磁盘 IO 打满——你能先在脑子里跑一遍"写产生新版本 → 旧版本成死元组 → VACUUM 回收 → 规划器按统计选路"这条因果链,定位到机制根因。这是只读官方文档给不了的整体直觉。

具体地,读完你能:

  • 读懂 EXPLAIN (ANALYZE, BUFFERS),从"估算行数 vs 实际行数"的偏差判断规划器为什么选错了计划。
  • 解释一个长事务为什么会让一批无关的表一起膨胀,并知道去查 idle in transaction。
  • 给定一条查询和数据分布,预测规划器会走 seq scan、index scan、bitmap scan 还是 index-only scan。
  • 说清楚什么场景该用 B-tree、什么场景该用 GIN / BRIN / 部分索引。
  • 对照 InnoDB 解释 PG 的"堆表 + VACUUM"模型,在迁移时避开默认隔离级别、聚簇索引假设等语义陷阱。

一句话本质

PostgreSQL 的几乎所有独特行为,都从一条规则推导出来:写操作从不原地修改数据。 UPDATE 和 DELETE 都只是写入新的行版本(tuple)、给旧版本盖上"失效"戳;每个事务读到的是某一刻的快照(snapshot)。再没有任何事务能看到的旧版本叫死元组(dead tuple),由 VACUUM 回收。

读不阻塞写、表会膨胀、长事务危险、count(*) 慢、index-only scan 为何依赖可见性图——全是这一条的推论。带着它读后面每一章。

现状速览 · 截至 2026-06

可当定论学的稳定核心:关系模型、MVCC、WAL、B-tree、cost-based 规划器,数十年没有结构性变化。本教程主线全部落在这一层。

近期在变(性能 / 运维侧):PG 17(2024-09)用 TidStore 重写了 VACUUM 的内存管理——旧的"给 VACUUM 把 maintenance_work_mem 封顶 1GB"调优经验已作废;PG 18(2025-09)引入异步 I/O(io_uring)、B-tree skip scan、虚拟生成列(现在是 GENERATED 的默认形态)。

已被取代、不要再学:recovery.conf(PG 12 起移除)、独占备份模式(PG 15 移除)、md5 口令(PG 18 起弃用,改用 scram-sha-256)。

最新稳定版 PG 18.4;PG 19 预计 2026-09 GA。正文以 PG 18 为基准,版本相关处会标注。

读之前 · 流畅感警告

这份教程会刻意制造一些"卡顿"——预测题、藏起来的答案、跨章的判别。它们让你慢下来,是设计,不是障碍。如果你发现自己在想下面三句话,停一下:

「我读得很顺」——顺,往往是熟悉感,不是学会了。机制题能复述吗?
「我做题很快」——快,多半是在套已经见过的题型,没碰到真正吃力的题。
「我没卡壳」——没卡,往往说明这一节没真正触动你已有的理解。

真正学进去的标志,是合上页面后还能把因果链画出来。第 7 章会让你这么做。

§概念地图

这张图是全篇的"挂钩"。后面每一章讲的东西,都能挂回这张图上的某个节点。现在扫一眼建立印象,每章开头还会回到它。

行版本 · MVCC 一行存在多个版本 决定可见性 先写日志·恢复 回收死元组 index-only scan 旧版本→ 存放于 按统计选计划 加速定位 快照 + 隔离级别 snapshot 死元组 dead tuple VACUUM / autovacuum 含冻结防回卷 规划器 + 统计信息 cost-based WAL 预写日志 索引 B-tree / GIN / BRIN 可见性图 visibility map 堆表 + 8KB Page + HOT 更新
图 0.1以"行版本 / MVCC"为中心的核心机制地图。注意三点:① 中心是"一行有多个版本",不是"一行一条记录";② VACUUM 不是可选的清理工具,而是这套机制的必需配套;③ 可见性图被 VACUUM 和 index-only scan 同时用到——它是连接"回收"与"查询"的枢纽。

§怎么读这份教程

全篇按 01 → 07 顺序读最完整。时间有限时,按目的走:

  • 只想建立整体心智模型:01 存储 → 02 MVCC → 03 回收·WAL,主线讲完了。
  • 正在排查性能 / 膨胀问题:02 MVCC → 03 回收·WAL → 05 规划器,直奔机制根因。
  • 从 MySQL 迁移或做选型:01 存储 → 02 MVCC → 06 对比 MySQL,看清两套架构的取舍。

§目录

§学完之后往哪走

  • pgvector / 向量检索——在你已经懂的"索引 + 规划器"之上,加 HNSW / IVFFlat 这层;RAG / Agent 场景的存储底座。
  • 逻辑复制与 CDC——把第 3 章的"WAL 逻辑解码"用起来,做数据同步与变更捕获。
  • 分区表与并行查询——规划器在超大表上的扩展,给第 5 章加一层。
  • 连接池(PgBouncer)——第 2 章的"每连接快照成本"在运维侧的应对。
  • 锁与 SSI 深入——行锁、谓词锁、Serializable Snapshot Isolation 的实现,第 2 章隔离级别的下一站。