PostgreSQL 万能论:一个数据库替掉你半个技术栈
文章摘要
作者 Raphael Bauer 是一位 CTO/过渡期管理者,开篇玩了个梗:万物的答案不是 42,而是 PostgreSQL。他从 2003 年一个叫 ColumbaDB 的研究项目开始用 PostgreSQL——Columba 早已消失,PostgreSQL 至今活得比谁都好。2003 年 MySQL 的使用面远大于 PostgreSQL,而且因为没实现全部 SQL 标准而可能更快;但 MySQL 缺了他们需要的东西(全文检索、强大的索引、SQL 标准合规性)。当年那个关键用例正是全文检索:他们本可以用 MySQL 加 Lucene/Solr,但那意味着要跑和维护两套系统、还要同步数据;PostgreSQL 用一个全文检索插件就在一套系统里搞定了,不需要同步、不需要两套运维。最近他还用 PostgreSQL 的 TimescaleDB 插件存超大量的网站分析时序数据(他的项目 Privatracker)。
他把 PostgreSQL 的威力归为三点:一是稳如磐石——PostgreSQL 是「无聊的老技术」,首个版本可追溯到 1996 年,用得广、用得久,数据库的 bug 要磨平需要时间,而 PostgreSQL 有过这个时间;社区很活跃,不断加功能却不破坏老部分,近年拿到了 JSON 文档存储、分区支持、公用表表达式等一堆现代特性。二是易于安装、运行和扩展——各大 Linux 发行版自带、Mac 上有 brew 和 PostgresApp,测试时配合 Testcontainers 可以让测试跑在和生产 100% 相同的真实 PostgreSQL 上,服务器上 apt-get 或 Docker 一把梭,AWS、GCP、Azure、ElephantSQL、CrunchyData、Timescale 等都是点一个按钮就能起并扩容。三是大幅简化 IT 架构——它不只是 RDBMS。
文章的主体就是一份「PostgreSQL 能替掉什么」的清单:
- 替掉 Solr 和 Elastic(全文检索)。 无需独立系统、语言无关、永远不会有数据与检索系统之间的同步问题。作者力推 Contentful 用 PostgreSQL 为用户实现全文检索的那篇文章,说这是「一个关于简洁如何撑起增长的故事」;Instacart 也一样,把现代检索基础设施建在 Postgres 上而不是另跑一个检索集群。内置的
tsvector/tsquery机制是很好的起点,属于原版 PostgreSQL、无额外活动部件,对绝大多数用例都工作得很好。如果长大到需要更好的相关性排序(BM25)或更强的可扩展性,也不必离开 PostgreSQL:Timescale/TigerData 的 pg_textsearch 提供 BM25 排序,ParadeDB 的 pg_search 基于 Tantivy 提供「Elasticsearch 级」的检索。 - 替掉 MongoDB(JSON 支持)。 PostgreSQL 对 JSON 的存储和查询(作者特意加了感叹号强调「查询」)支持极佳,还有 GIN 索引类型让这些操作飞快。他引了 The Guardian 从 Mongo 迁到 PostgreSQL 的文章,以及 Hazel Bachrach 关于 jsonb 注意事项的文章(她那篇《What I Wish Someone Told Me About Postgres》也被强烈推荐)。
- 替掉 Kafka 和 RabbitMQ(消息队列)。 魔法来自
SELECT .. FOR UPDATE和SELECT .. SKIP LOCKED,用这两个特性就能把一张表当队列用——既可以是带游标、多消费者的持久化方式,也可以是读一次即消费的方式。他的建议是:先用 PostgreSQL 做队列,只有当它真的不再够快时再换 Kafka、RabbitMQ 或 SQS,「你会惊讶于 PostgreSQL 有多好用」。 - 替掉 ClickHouse(高吞吐时序数据)。 时序数据的特点是短时间涌入大量数据点、然后要频繁聚合与统计。ClickHouse 这类专用系统很棒,但 Timescale 插件能做到几乎相同的事,而且不用学新东西、不用多维护一套。
- 当向量数据库用于 AI 工作流。 pgvector 把 PostgreSQL 变成向量库,让你用已经熟悉的技术做索引和检索——这是 LLM 工作流的核心一环;Timescale 的 pgai 除了包含 pgvector,还带一堆让索引数据、调 LLM、按相似度检索变得极简的扩展。
- 替掉 Redis(非持久化高性能缓存)。 缓存按定义可以丢数据、可以从源头重建。秘诀是用 UNLOGGED 表,甚至可以用触发器模拟 Redis 的自动过期。
- 替掉文件系统(存原始二进制数据)。 有个客户的场景是要读写海量的小块二进制编码信息,团队最初以为走文件系统最快,性能实测却发现 PostgreSQL 更快——它对文件系统的使用非常高效,还叠加了大量缓存和高效读写策略。他们用 Flatbuffers 把数据存进 blob 列,在客户端反序列化。
- 替掉图数据库。 层级数据当然可以用递归查询,但那既难读难维护难调试、性能也不谈了;更好的办法是 PostgreSQL 的 LTREE 类型,他不止一次靠它实现层级标签结构。而如果需要的是真正的图——节点、边、属性、任意方向遍历——通常这时有人会提议往栈里加 Neo4j,随之而来的是又一套要运维的系统、又一套备份策略、又一次数据同步。不必如此:Apache AGE(A Graph Extension)把 PostgreSQL 变成图数据库,它是 Apache 软件基金会的顶级项目,实现 openCypher,也就是你在 Neo4j 里用的同一种查询语言;最妙的是图查询和普通 SQL 活在同一个数据库里,能在一条语句里组合,写法是
SELECT * FROM cypher('my_graph', $$ MATCH (a:Person)-[:WORKS_AT]->(c:Company) RETURN a.name, c.name $$) AS (person agtype, company agtype);。建议和队列一样:先用 PostgreSQL,真撞到极限再上专用图库。 - 替掉你的微服务。 如今大部分「微服务」无非是模型、从数据库取数、返回 JSON 给客户端;而 PostgreSQL 能把任意查询变成 JSON 结果,这实际上替掉了服务端中间层。他引用 Lukas Eder 的文章,说其中提到的一切在 PostgreSQL 上都很可行。
- 替掉你的 PlayStation 5。 有爱好者用纯 SQL 的公用表表达式实现了俄罗斯方块。「疯了。也许不该太当真。」
结论:这份清单并不穷尽,PostgreSQL 是非常灵活的软件,还能靠插件不断变强。想跑得快就需要简洁,所以碰到新需求时永远先问:PostgreSQL 不能做这个吗?我们真的需要那个闪亮的新技术 X 吗?「PostgreSQL 也许不是万物的答案,但它是远比你以为的更多问题的答案。」文章还在开头就加了一句更新,说这个话题在 HN 上被讨论过,那个帖子里有大量额外链接、真实经验和批判性观点,很值得一读。
HN 评论精华
这条帖子 438 分、267 条评论,是本组里最长也最有火药味的讨论。HN 的走向和文章标题并不一致:真正吵得最热的不是「Postgres 能不能替掉 X」,而是(一)2003 年 MySQL 与 PostgreSQL 的历史恩怨为什么以 Postgres 胜出收场、(二)SQLite 派对「连 Postgres 都是过度设计」的反向倡议、(三)一大批实战派对「Just use Postgres」这句口号本身的强烈反弹——包括一位 Postgres 长期贡献者亲自出来说这类文章「让人厌烦」。
- rwultsch 一上来就挑文章第一段的刺:「MySQL 也可能更快因为它没实现全部 SQL 标准」这个开头不好,他认为这指的是 MyISAM,而 MyISAM 已经十多年不相关了,InnoDB 只是做了和 PG 不同的设计取舍,在点查上曾经(也许至今)更快。radiospiel 替作者辩解说原文明确讲的是 2003 年。browningstreet 补了一句时代背景:那会儿 MySQL 是每个 PHP 主机商的默认选项,那才是它后来丢掉的市场——「它们是数据库界的 Perl」。actionfromafar 阴阳了一句:早期 MySQL 不是对「真的刷盘到磁盘」这件事挺随性的吗?那也很快,web scale 的快。
- 关于 Postgres 为何反超,roryirvine 给了最完整的时间线:早年 PostgreSQL 麻烦得多,先是容易崩,后来还有升级必须 drop 库那套事,运维上直到 2002 年左右才追平 MySQL;dot com 时代常见做法是先用 MySQL 开发上线、真做大了再迁走(但典型 LAMP 开发者觉得 Oracle 和 SQL Server「非常怪」,很多人宁愿忍着 MyISAM 的已知缺陷留在 MySQL);他的判断是 2000 年代中期以后 PostgreSQL 对新项目明显更优,但真正把存量用户推离 MySQL 的是 Oracle 收购。jeremyjh 认为 Postgres 真正超越的其实不是 MySQL 而是 Oracle、SQL Server、Sybase;他也指出 MySQL 长期有个运维优势是很早就有主主复制,那是选它的真实理由,而 Postgres 至今没有原生主主(Citus 也不算同一回事)。roryirvine 接着回忆自己在一家线上零售商早期就用了 MySQL 主主复制,「相当有趣的体验」,对 binlog 的各种怪癖变得非常熟悉;他还提到 O’Reilly《High Performance MySQL》第二版篇幅翻倍,多出来的页数大部分在解释为什么依赖主主之前要非常小心并大量测试。oblio 补了个很少被提的点:PostgreSQL 直到 2010 年左右才有真正的 Windows 支持,而当时连 LAMP 开发者也大量在 Windows 上写代码。_flux 总结气质差异:Postgres 正确性优先、性能其次,MySQL 反过来;他还点出 MySQL 至今不支持事务性 DDL,而这对 schema 迁移非常有用。williamdclt 给了三条具体差距:MySQL 查询规划器差得多(他前一天刚靠
USE INDEX把一个查询加速 300 倍,几乎肯定 Postgres 会自己选对)、索引类型少(没有 GIST、没有 GIN)、没有事务锁(Postgres 的pg_advisory_xact_lock),他只能自己用一张锁表实现。atherton94027 反过来说至少 MySQL 还给你USE INDEX,Postgres 上「规划器某个开关一翻、生产上突然选了个奇怪索引导致性能崩掉」并不罕见;tux3 告诉他好消息是 pg19 加了计划稳定性特性(pg_plan_advice),本质是完整的规划器提示。farlight 提供了 MySQL 侧的新进展:新的「hypergraph」优化器即将成为默认,他维护的一个 CRUD 但业务逻辑复杂的应用在多表 join 报表上有大幅提升,而旧默认优化器在某些病态情形下比 PostgreSQL 慢 8–10 倍,新优化器把两者拉得很近。 - SQLite 派也有相当声量。replwoacause 说自己什么都用 SQLite,知道并发写者的问题但在他的规模下根本无所谓。Tsarp 给出了组合方案:NVMe 盘 + Litestream + 对象存储(S3/R2),足够覆盖那条「不是 Uber 和 AirBNB」的长尾。TekMol 列了 SQLite 的优势:没有守护进程、一个库一个文件、配置负担更小;BowBun 立刻反列 Postgres 的优势:支持每进程多于一个写者、严格类型、访问控制、复制在规模上比复制粘贴文件更高效。类型系统是 SQLite 被攻击最多的点,Thaxll 说测试一个应用时被它糟糕的类型系统「震惊」;OutOfHere 问 STRICT 表还不够吗,lenkite 回答要的是 SQL-92 标准的 DATE/TIME/TIMESTAMP,被问「不能存成整数吗」时列出四条:没有数据完整性、没有自动格式化、没有时区支持、没有标准日期函数。关于「本地用 SQLite、生产切 Postgres」,thatwasunusual 说自己在 .NET + EF Core 下就这么干,本地开发甚至 staging 用 SQLite、上生产「翻一个开关」;zelphirkalt 强烈反对,他在一个小 Django 项目上这么试过,一次又一次撞到 SQLite 或 Django 的 SQLite 适配器在多对多关系和中间表上的限制,只能写各种绕法,而这些绕法在生产的 PostgreSQL 上未必等价——保持测试/开发环境尽量贴近生产是基本实践。Merad 从类型差异角度补刀(SQLite 偏爱把东西存成字符串),并说 Docker 里跑 Postgres 太容易了,他看不出本地用 SQLite 的好处;KronisLV 和 zelphirkalt 都推荐 Testcontainers。
- 对「Just use Postgres」这句口号的反弹是全帖最精彩的部分。devin 直言这类文章(Postgres!你只需要它!)已经很令人厌烦:Postgres 连第一条 Elastic 都远远替不掉,整份清单顺下来都是「是的,在极其基础的用例下 Postgres 可以代替它,但你一旦真的需要这些工具的能力,一切就都不成立了」。最有分量的是 anarazel(长期参与 Postgres 开发的核心贡献者)的回应:「说实话,我作为一个在 Postgres 上工作很久的人,也觉得这挺烦的。有很多东西我不会用 Postgres 做,而我大概比多数人更能从它身上榨出东西。」switchbak 补充说这类推荐往往不给上下文和规模前提:Postgres 在小规模下能干很多事,按它的强项用甚至能撑到惊人的规模,但如果拿它做不擅长的事、又在不合适的规模上,几乎必然出问题,而事后解决那些问题往往比一开始就选个更合适的方案更难——「不过我觉得年轻/经验少的工程师大概总得先烧到自己一次,所以这话题永远死不掉」。
- 反方的反方同样有力。dewey 说重点是让人「先考虑一下」:很多人在个人项目或公司内部项目上还没开始就把 Elastic、Redis、Postgres、Kafka 一起立起来了,实际上塞进 Postgres 能顶很久;没人在说一个带复杂筛选检索逻辑的大型电商该扔掉 Elasticsearch 集群。devin 反驳说一旦真去做,你往往开始看自定义 pg 扩展,那等于是决定「简化技术栈」的同时去维护一个带自定义扩展的 Postgres 集群,只是嘴上还说「反正还是 postgres 嘛」。pphysch 火力更猛:安装维护一个 Postgres 扩展比运行 Elasticsearch 和 Kafka 简单得多得多,「如果你懂自己在说什么,这两件事怎么可能相提并论?」devin 让了一半:跑个小 ES 双写并不难,Kafka 确实运维重,但他只会在问题本身是 Kafka 形状时选 Kafka,而那种情况下他绝不会选 Postgres——把 Kafka 等同于「我需要一个队列」是可笑的类比。kumarvvr 提供了一个典型体验:给一个小应用装配 rabbitmq,装好配好却不工作,跳了一天的火圈;扔掉换 Postgres,半小时搞定,跑得很好。otherme123 归纳了普遍心态:共识似乎是「Postgres/SQLite 对 99% 的情况都行,但『我的』情况一定在那 1% 里,因为我要成为下一个 Facebook」。
- 0cf8612b2e1e 指出这场争论的根源是两拨人各说各话,建议这类文章都标注规模:一拨是「我的 B2B 应用只有 Postgres,5 万月活完美够用,两人团队睡得很香」,另一拨是「我在 FAANG,10 亿日活,这是个笑话,会立刻倒掉,我们有专门的 Kubernetes、Elastic、Redis 运维团队」。rtpg 补充说连 B2B 与 B2C 的分野都很大:有很多专业 ERP 用户数不多但要处理的数据量很大,数据规模、读写比、请求数都是会改变「只用 pg 有多痛」的独立维度。
- Gluber 给出了全帖最细的逐条技术审视:作队列——只在需求非常基础时可行;高吞吐时序——TimescaleDB 能用,但从运维角度看在同一台 DB 服务器上与其他负载共存很糟;向量库——同样问题,pgvector 活在自己的「世界」里,查询规划器把它看成非常不透明的东西,别想着给一个还要服务复杂查询的高吞吐库加向量存储,pgvector 要么把你的缓存冲掉、要么把 CPU 吃满,让本来正常的负载卡住;他强调这不是 pgvector 的问题(对作者们表示敬意),而是 PostgreSQL 的扩展 API 不太擅长把自定义代价和取舍暴露给整个系统。他还补了个规模数字:pgvector 只有 HSNW 和 IVFlat 索引(持久化方案里也没有更好的),但在超大向量量(1 亿以上)时延迟会崩——听起来很高,可生产 RAG 系统往往做逐 chunk 嵌入甚至视觉 patch 嵌入,一页文档就能变成 1024 个向量,于是 10 万页就撞到上限,而这是大型组织肯定有的量级。存原始数据——小文件行得通,大量数据存进去他觉得费解,真正闪光的是访问「大量小文件」时内部缓存等机制带来的优势。微服务——如果一个服务只是从某个数据库模型里吐 JSON,那它根本不该存在,建个视图就完事了。
- OLAP 这条线上,ericpauley 指出文章原文写的是「PostgreSQL Replaces Clickhouse」,而他在 ClickHouse 里存了几十亿行、做了几十个物化操作,「想想在一个连声明式 IVM(增量视图维护)都不支持的库里那会是什么样,我打寒战」。tpetry 回应说文章建议的是 TimescaleDB,它有自己的 IVM 概念——连续聚合,而且相比 ClickHouse 的做法,它在你更新/删除历史原始数据时也能更新物化视图。jeremyjh(自称 Postgres 的大粉丝)给了最平衡的一段:在对象存储上运行的列式 OLAP 引擎能做的事比 Postgres 好太多,几乎可以说是完全不同的能力;但重点仍是「只用 Postgres 你能走得比很多人以为的更远」,现在还多了 pg_lake 这类选项——不过他也说「我真希望自己早得多就换了分析平台」。Tostino 提到自己已经在 Postgres 上做 IVM 很久了(commitfest 的一个 patch),虽然还不完全声明式,但至少能把 IVM 带进内核让大家用上。
- 一些有用的补充链接和更正:_joel 抱怨文章没提 PostGIS,「可耻」。jihadjihad 指出图数据库那节可以更新——PG 19 已经原生支持属性图(property graphs),可以把表和关系定义成节点/边,然后用类 Cypher 语法查询。HighlandSpring 给了一个真实的大规模案例:Revolut 这家银行的全部事件持久化和流式处理都建在 Postgres 上,栈里没有传统的消息队列/broker。idoubtit 列了三条被文章隐藏的 Postgres 局限:MySQL 不需要连接池而 Postgres 的很多用例需要 PgBouncer 之类;MySQL 有大小写不敏感的 UTF8 collation,多语言文本排序和基础检索更简单;MySQL 不需要 VACUUM,而 VACUUM 可以是个难题。sgarland 补充说 Postgres 也能做大小写不敏感,只是不是默认,需要
CREATE COLLATION ... provider = icu, deterministic = false, locale = 'und-u-ks-level1'。sgarland 另一段对比很值得记:MySQL 用默认调参一般就能跑得不错(只要 buffer pool 相对内存大小设对,云厂商会自动做),有些旋钮能榨性能、也有些默认值很糟(lock_wait_timeout默认设成一年……),但总体不需要太多照料;Postgres 则有上百万个旋钮、很多互相影响、有些还能找到互相矛盾的建议,而且如果不盯紧长事务它会迅速倒掉——在大多数场景下它比 MySQL 更快(clustered index 你好),前提是你调对了。「这就是为什么每次有人鹦鹉学舌地说『Just use Postgres』好像能解决一切问题时我都很挫败。它是极强大的工具、确实能替掉你栈里的大部分,但它也真的、真的希望你去读手册——不是随便的 Medium 博文,是官方文档。」philippemnoel(ParadeDB 员工)承认「原版 Postgres 远远替不掉 Elastic」是对的,但有人在解决这件事;他把 disclaimer 用错成 disclosure 还被 majewsky 纠正了。