跳转到主要内容

关于此书

PostgreSQL 18 · 基于俄文 PG18 原版的简体中文译本

“原来一切都这么简单!”什蓬季克(Шпунтик)叫道,“可我好像在哪儿读过,作家得有点想象,有点构思……”

“嗨,构思!”斯梅卡伊洛(Смекайло)不耐烦地打断了他,“只有书里才说要有构思。可你试着构思点什么吧,人家早就把什么都想过了!无论你想写什么,全都有人写过。”尼古拉·诺索夫,《小无知和他的朋友们历险记》

本书适合哪些人

本书适合那些不愿把数据库当作黑箱来使用的人。如果你充满好奇,不满足于权威人士的建议,想亲自弄清一切,那么我们就同路了。

我假设读者已经有一定的 PostgreSQL 使用经验,至少大致了解它是怎么回事。对完全没有经验的新手来说,本书可能有些难。例如,我不会介绍如何安装服务器、在 psql 中输入命令或修改配置参数。

我希望这本书对那些熟悉其他数据库系统的内部结构,但想转而使用 PostgreSQL 并希望了解两者之间差异的人也有所帮助。几年前,如果有这样一本书,我本可以节省很多时间。这也正是我最终写下这本书的原因。

本书不提供的内容

本书不是一本现成方案集。我们不可能为所有情况准备好解决方案,但理解复杂系统的内部机制,就能批判性地重新审视他人的经验,得出自己的结论。这正是我介绍那些乍看似乎没有实际用处的内部细节的原因。

本书也不是一本教材。它深入讨论了某些领域(也就是我自己更感兴趣的领域),却绕过了另一些领域。如果你正在学习 SQL,可以看看叶夫根尼·莫尔古诺夫(Евгений Моргунов)的教材 《PostgreSQL:SQL 语言基础》1;而鲍里斯·诺维科夫(Борис Новиков)的 《数据库技术基础》2 则能提供必要的理论基础。

本书也无意充当参考手册。我力求准确,但没有打算用它替代文档,因此会略去一些在我看来无关紧要的细节。遇到任何不明白的地方,请阅读文档。

本书不会教你如何开发 PostgreSQL 内核。我不要求读者掌握 C 语言,而是面向管理员和应用开发者。不过,我会经常引用源代码,从中你可以了解到任意多的细节,甚至比你想知道的还多。

本书提供的内容

在绪论中,我会简要介绍后文所依赖的基本概念。我想你几乎不会从这一章学到什么新东西,但为了让全书内容完整,还是把它放了进来。此外,它也可能对从其他数据库管理系统转来的读者有所帮助。

第一部分讨论一致性与隔离性。我先从用户的角度介绍这些问题(有哪些隔离级别,它们会带来什么影响),然后转向内部实现。为此,需要深入介绍多版本机制和基于数据快照的隔离机制的实现细节。其中,清理过期行版本的过程尤其需要仔细讨论。

第二部分介绍缓冲区缓存,以及能够在故障后恢复一致性的机制——预写式日志。

第三部分详细介绍各个层级的锁的结构和使用:用于内存的轻量级锁、用于关系的重量级锁,以及表中的行级锁。

第四部分解释服务器如何规划和执行 SQL 查询。我会介绍有哪些数据访问方式、采用了哪些连接方法,以及如何使用统计信息。

第五部分把此前局限于 B-树(B-tree)的索引讨论扩展到其他访问方法。我首先介绍可扩展性的一般原理,它们界定了索引系统核心、索引访问方法和数据类型之间的边界(为此需要引入操作符类的概念),然后详细介绍每种现有方法的特点。

PostgreSQL 自带了大量“自省”扩展,日常工作并不需要它们,但它们让我们能够窥见服务器内部的运行情况。本书使用了其中的许多扩展。除了帮助我们深入了解服务器的内部结构,这些扩展也能使复杂情况下的诊断更容易。

约定

写作时,我尽量让这本书能够按顺序逐页阅读。但很难一次把所有事情讲清楚,所以同一话题不得不反复出现。如果每次都写“后面还会讨论”,书就会厚上许多。因此,遇到这种情况,我会在页边标出继续讨论该话题的页码。同样,指向前文的页码表示前面已有相关讨论。(第 19 页)

本书正文和全部示例均适用于 PostgreSQL 18。有些段落在页边标注了版本号,表示该段内容从所标注的 PostgreSQL 版本起成立,而更早的版本要么没有所述功能,要么采用了不同的实现。这些标记可能对尚未升级到最新版本的读者有用。(v. 18)

页边还会标出所讨论参数的默认值。参数名(包括普通参数和存储参数)以斜体表示:work_mem。(默认值: 4MB)

我在脚注中经常引用一手资料。这类资料有好几种,首先是蕴含丰富信息的文档3。文档是项目的有机组成部分,始终由开发者亲自维护更新。不过,最根本的资料无疑是源代码4。即使不懂 C 语言,仅从注释和 README 文件中就能找到如此多问题的答案,实在令人惊叹。我偶尔也会引用 commitfest 条目5:在 pgsql-hackers 的通信中,总能追溯变更的历史,理解开发者作出决定的思路,代价则是需要阅读海量讨论。

说明

有些题外话和说明可能让人偏离主线,但我还是忍不住把它们写进书里。这些内容会采用这样的形式标出,方便读者跳过。

当然,本书有很多代码片段,主要使用 SQL。代码以 => 作为提示符;必要时,后面还会给出服务器的响应:

=> SELECT clock_timestamp();
        clock_timestamp
-------------------------------
 2026-04-05 20:51:34.767686+03
(1 row)

如果在 PostgreSQL 18 中仔细执行书中的所有命令,应该能得到相同的结果(当然,事务编号等无关紧要的细节可能不同)。至少,本书中的所有代码都是执行一个脚本所得的结果,而该脚本包含的正是这些命令。

需要展示多个事务同时运行时,在另一会话中执行的代码会以缩进和竖线标出:

=> SHOW server_version;
 server_version
----------------
 18.3
(1 row)

要重现这些命令,打开两个 psql 终端会很方便(和任何实验一样,这对自学很有帮助)。

单独提到的命令和各类数据库对象名称(如表、列、函数和扩展)采用等宽字体:UPDATE、pg_class。

从操作系统调用工具时,使用以 $ 结尾的提示符:

postgres$ whoami
postgres

我使用 Linux,但没有涉及它的特有功能;掌握最基本的知识就足够了。

致谢

一个人无法独力完成一本书,这正是向那些热心人道谢的好机会。

感谢 Pavel Luzanov,他在恰当的时候建议我做一点真正有价值的事。

感谢 Postgres Professional 公司,让我不必只在业余时间写作这本书。公司是由人组成的,我尤其要感谢 Oleg Bartunov 源源不断的精力和想法,也要感谢 Ivan Panchenko 的全面支持和 LATEX。

感谢教育部门的同事们营造的创作氛围,以及大家的讨论。培训课程的内容和讲授方式正是在这些讨论中逐渐形成的,也体现在了本书中。感谢 Pavel Tolmachev 对草稿的仔细审读。

本书许多章节最初以文章形式发表于 Habr6,感谢读者的意见和反馈。这些反馈让我看到了这项工作的必要性,发现自己知识中的空白,也让书稿得以改进。

感谢 Liudmila Mantrova,她为打磨本书的语言付出了大量心血。如果你读起来不至于每隔一句就磕绊一次,那都是她的功劳。

书中没有逐一提到这些人的名字,但我介绍的每个函数和每项功能背后,都有具体的人为之付出了多年的劳动。我敬佩 PostgreSQL 的开发者,也格外荣幸能称其中许多人为我的同事。