数据库技术观点评论分析· 3242 字· 约6分钟阅读

Postgres 不慢,慢的是你那块云盘

A
AI编辑团队AI 原创内容
2026-10-12 17:25 发布· 本文由作者与AI协作完成
本内容由人工智能生成,仅供研究参考,不构成投资建议。
💡

POSETTE 2026 上,ClickHouse 产品负责人用一组对比实验证明:同一份 PostgreSQL 负载,本地 NVMe 跑出 16,030 TPS,EBS 只有 1,734 TPS,差距 9.24 倍。结合玩家老C的 SQLite B-tree 源码系列,本文讨论数据库性能的真实瓶颈与工程护城河。

9.24 倍。同一份 PostgreSQL 负载,只把存储从 EBS 换成本地 NVMe,TPS 就从 1,734 跳到 16,030。POSETTE 2026 上 ClickHouse 产品负责人 Sai Srirampur 的这场实验,把一个业内心照不宣的事实摆上了台面:很多所谓的「数据库慢」,其实是存储慢。与此同时,博主 玩家老C 的 SQLite B-tree 源码系列,从另一个方向提醒我们——理论算法到生产实现之间,隔着的才是真正的护城河。

📉 一次跑给所有人看的对比实验

数据库圈最贵的成本,常常不是许可证,而是错怪的锅。

POSETTE 是 Postgres 社区一年一度的线上技术活动,2026 年这一届上,ClickHouse 产品负责人 Sai Srirampur 的演讲标题相当直白:《Postgres Isn't Slow. Your Storage Is.》——Postgres 不慢,是你的存储慢。

为了证明这一点,他跑了组对比:同一份 PostgreSQL 负载,分别放在本地 NVMe 和 EBS 上各跑一遍。结果差距悬殊——事务吞吐差了 9.24 倍。

指标本地 NVMeEBS 云盘差距
事务吞吐(TPS)16,0301,7349.24 倍

为什么一家以 OLAP 分析型引擎立足的公司的产品负责人,要替 Postgres 这个 OLTP 数据库「辩护」?因为在云数据库的计费与归因体系里,存储的账总是记在数据库头上。用户看到的诊断结论是「Postgres 慢」,买单动作是升级实例规格、加读副本;而真正该被审视的那块盘,从头到尾没人看一眼。

这个实验的价值不在结论新颖——资深 DBA 早就知道 fsync 是事务提交的命门——而在于把归因做成了可复现的数字。当「换存储」第一次有了谈判筹码,云上数据库的选型逻辑就该被重写一遍。

🧱 云盘的「物理税」

云盘上的每一次写,本质上都是一次迷你远程调用。

想象一笔转账事务:PostgreSQL 提交时必须先写 WAL 日志并 fsync 刷盘,确保崩溃后可以恢复。在本地 NVMe 上,这是一次微秒级的 PCIe 操作;在 EBS 上,同一次 fsync 要穿过虚拟化层、网络传输、远端落盘,变成一次毫秒级的远程写。⚠️ 每个事务提交都要交一遍这笔「物理税」,9 倍的吞吐差距,就是这样一笔一笔累出来的。

EBS 这类弹性块存储的价值很清楚:快照备份、随时扩容、故障时卷可以跟着实例漂移。这是云厂商把计算与存储分离后卖给你的灵活性。但灵活性有价签——延迟和抖动。对分析型负载,大块顺序读可以把网络往返摊薄;对高并发小事务的 OLTP,每一笔都要单独付一次远程写的税,这是最坏的组合。

行业其实已经在往回走:各大云厂商都在推挂载本地 NVMe 的实例形态,用「本地高性能盘 + 云盘做持久层」的分层来补救。DBA 圈子里流传一句自嘲:「参数调一天,不如盘换一换。」玩笑背后是个严肃判断——弹性与延迟是一对明码标价的兑换关系,存储选型必须按负载形态对号入座,不存在万能的默认选项。

🔧 理论到实现之间隔着一条护城河

论文里的 B-tree 只有几十行,生产里的 B-tree 有几万行。

玩家老C 早几年在数据库公司做开发时,一直有个疑问:教科书上的 B-tree 算法,最终如何落地为一个生产上的实现?后来他把这个问题做成了一个系列——《SQLite 3.36 版本 B-tree 实现》。开篇概述里,他列出了一串教科书从不回答的问题:

  • 如何处理不同大小的数据的存储?
  • 删除一个数据之后,如何复用其留下的空间?
  • 错误、崩溃发生时,如何保证不写坏一个页?

SQLite 没有独立服务器进程,一个文件就是一个库,恰恰是这类「不优雅的实现细节」层层堆叠,让它成为部署范围最广的嵌入式数据库。页怎么布局、空闲页链表怎么维护、崩溃后怎么靠日志回滚到一致状态——这些内容不会出现在任何算法论文里,却决定了数据库在极端场景下的可靠性。

这几年的数据库创业与开源热潮里,人才多集中在架构设计、SQL 层优化器这些「高大上」的环节;真正逐行读存储引擎源码、把边角 case 一个个补齐的工匠环节,依然稀缺。据多位长期做内核开发的从业者私下讲,团队里能独立读懂一个生产级 B-tree 实现的人,往往一只手数得过来。老C 这类系列文章的价值,是把「如何读一个生产级实现」的方法论公开出来——这是给整个行业补课。

🛠️ 先看盘,再调库,最后才轮到参数

排查性能问题,很多人第一步就走反了。

把 Sai Srirampur 的实验和 玩家老C 的源码笔记放到一起,能得到一条朴素的行动准则:当数据库变慢,先怀疑存储,再怀疑实现,最后才去拧参数。💰 对云上团队来说,这意味着几件具体的事——

第一,复现要贴近生产负载。TPS 数字只在同样的负载形态下才有意义,跑个玩具压测就下结论,是另一种自欺。第二,监控要看穿到存储层。数据库自带的指标通常止步于「查询耗时」,云盘的 IOPS 配额、吞吐上限、fsync 延迟,需要单独建面板。第三,选型时把存储当一等公民。高频小事务的 OLTP,优先考虑本地 NVMe 实例形态,或者为 EBS 明确预留足够的 IOPS 预算;分析型大扫描则相反,弹性云盘的摊薄成本可能更划算。

更深一层的判断是:云成本优化的下一站,不是无脑给数据库实例升配,而是「存储匹配负载」。当一块盘贡献了 9 倍的性能差距,它同时也是 9 倍的成本杠杆——用对了是红利,用错了是长期失血。

小结

两条线索,一个结论:性能问题的第一性原理在 I/O,护城河的最后一公里在实现。Sai Srirampur 用 9.24 倍的对比数字把存储的账算清了,玩家老C 用 SQLite 源码系列把实现的地基翻开了——它们共同消解的是「换个数据库/换个架构就能解决问题」的捷径幻想。接下来值得盯的是:本地 NVMe 实例与云盘分层方案会否成为云数据库的默认形态,以及「读源码、抠实现」这堂补课,行业还要上多久。