2026-09-24
· Dylan YuMySQL vs PostgreSQL:2026 年的实用决策框架
MySQL 和 PostgreSQL 都很成熟、都很出色,也都仍然值得你刻意去选择。这里有一套诚实的框架,帮你在两者之间做选择——各自真正胜在哪里、在生产环境里什么会咬你一口,以及什么时候答案干脆就是"两个都用"。
这场争论的两边我都站过,也亲眼见过它往两个方向都走得很难看。
PostgreSQL 阵营会告诉你这根本不成问题——MySQL 是遗留数据库,Postgres 才是正确选择,别纠结了。MySQL 阵营会告诉你 Postgres 又慢又过度设计,适合业余玩家,一上负载就拉胯,而 MySQL 已经撑起半个互联网二十年了,那还有什么可争的?
这两种说法都很偷懒,而且来自同一个地方:这些人深度用过其中一个数据库,另一个却几乎没碰过。如果你在 Postgres 里泡了五年,MySQL 的怪癖看起来就像设计缺陷。如果你在 MySQL 里泡了五年,Postgres 的繁文缛节看起来就像额外开销。两个人都没说谎,但谁也没给你完整的画面。
诚实的表述是这样的:MySQL 和 PostgreSQL 都很成熟、都经过实战检验,也都能扛起严肃的生产负载。2026 年真正重要的差异比网上暗示的要窄——但它们是真实的,而且对应到你工作负载、团队和部署环境的具体情况上。
所以我们就真的把它们过一遍。不是当作记分牌,而是当作一组你可以针对自己具体情况做出的决策。我会告诉你各自赢在哪里、各自在生产环境里哪里会让你意外,以及如果你是那个必须长期和它相处的人,该怎么思考这个选择。
两种架构,以及为什么它们的差异没你想的那么大
先从它们的共同点说起,因为这比舆论暗示的要多。
MySQL 和 PostgreSQL 都是客户端-服务器的关系型数据库管理系统。两者都作为独立的守护进程运行,监听网络端口,使用一套通信协议,认证客户端,并通过连接提供 SQL 服务。两者都用 MVCC(多版本并发控制)实现 ACID 事务,这意味着读取者不阻塞写入者,写入者也不阻塞读取者。两者都支持外键、索引、触发器、存储过程、视图和复制。两者都是开源的。两者背后都有数十年的生产历史,也都在各大云上提供托管服务。
如果你是从 SQLite 过来的——那里数据库是一个链接进你进程的库——这就是共同的起点。两者都预期自己住在一台保持开机的机器上,按计划备份,并通过网络被连接。你已经知道的关于运维数据库服务器的一切,对两者都适用。
这个共同的基础正是这个问题如此难分伯仲的原因。你不是在两种计算哲学之间选择。你是在同一个理念的两种实现之间选择,而不同的优先级被烘焙进了细节里。
而真正的差异就活在细节里。我会把它们归结为四个方面:
- 类型系统。 PostgreSQL 自带一套丰富得多的原生类型——数组、范围、几何类型、
JSONB、UUID、网络地址类型等等——还允许你定义自己的类型。MySQL 的类型系统更窄,历史上对存储的内容也更宽松。 - 扩展模型。 PostgreSQL 就是为在进程内被扩展而设计的。你可以加载像 PostGIS 或
pgvector这样的扩展,在数据库层获得全新的能力。MySQL 有一套插件系统,但那不是同一种生态。 - 默认值。 PostgreSQL 默认严格——类型不匹配会报错,约束被强制执行,你必须主动选择退出正确性。MySQL 历史上默认宽松,你必须主动选择进入严格模式。
- 生态。 MySQL 是互联网很大一部分的默认数据库——尤其是 PHP、WordPress 和共享主机。PostgreSQL 是另一部分的默认——分析、地理空间,以及想在数据库内部做更多事的团队。
注意,这些没有一条是"其中一个更快"。两者都快。两者的查询规划器都好到让你的 schema 设计和索引比选了哪个引擎更重要。如果你是因为原始性能在两者之间做选择,那你优化错了东西——我稍后会回到这一点。
这篇文章剩下的部分,就是把这四个方面变成一个你站得住脚的决策。
MySQL 胜在哪里
先从 MySQL 说起,因为"MySQL 是遗留的"这种说法抹掉了很多真实的优势。
无处不在与托管
这是 MySQL 最大的结构性优势,而且甩开对手很远。如果你租一台服务器或一个共享主机方案,MySQL(或它的分支 MariaDB)几乎肯定已经装好并配置好了。如果你在大多数云服务商上开一个托管数据库,MySQL 是列表里最靠前的选项之一。如果你在用某个框架或 CMS,它的默认数据库十有八九就是 MySQL。
这种无处不在有复利效应。每个主机商都知道怎么跑它,每个系统管理员都运维过它,每一篇"怎么把我的应用连到数据库"的教程都有一个 MySQL 标签页。当你选择 MySQL,你是在海量部署环境里选择了阻力最小的那条路——而这种摩擦的减少值真实的时间和金钱。
PHP 和 WordPress 生态
WordPress 跑在 MySQL 上。Drupal、Joomla、Magento,以及支撑着互联网相当一部分的一长串 PHP 应用也一样。如果你的工作涉及其中任何一个——写插件、维护网站、迁移内容、调试主题——不管你选没选它,你都会和 MySQL 打交道。
这不是小众。单是 WordPress 就跑了惊人比例的网站,围绕它的整个生态——主机、插件、代理公司、自由职业者——都建立在 MySQL 之上。如果那就是你工作的世界,选择 Postgres 意味着在每个项目上都要和生态对着干。这里选 MySQL 是对的,不是因为它在技术上更优越,而是因为它就是你所工作平台的原生语言。
简单的读多工作负载
对于一个传统的 web 应用——请求进来,你读一些行,渲染一个页面,偶尔写入——MySQL 非常出色,而且它已经为这种模式调优了几十年。它是一匹干活的老黄牛。读多的 CMS、产品目录、会话存储、内容站点:MySQL 处理这些全都不在话下。
MySQL 赢得"快"这个名声的原因大体如此:它很早就被激进地针对主导互联网的读多、高连接数的 web 工作负载做了优化。并不是说 MySQL 本质上比 Postgres 快——在很多工作负载下并非如此——而是它在构建时就把常见的 web 场景放在心上,这在默认值里看得出来。
熟悉度与工具
会 MySQL 的人比会 Postgres 的人多。这是一个招聘考量、一个入职考量,也是一个"凌晨三点它崩了我该问谁"的考量。MySQL 的工具生态极其庞大——每个 GUI 客户端都支持它,每个 ORM 都支持它,每个云服务商都提供它,而且你碰到的每一个错误信息背后都有二十年的 Stack Overflow 答案存档。
对于没有专职数据库专家的小团队,MySQL 的熟悉度是一个真正的运维优势。最好的数据库就是你的团队能自信运维的那个。
PostgreSQL 胜在哪里
现在说另一边,同样诚实。
严格性与正确性
PostgreSQL 的默认姿态是:数据库应当保护你的数据不受你的应用伤害。类型被强制执行。约束不可商量。如果你试图把字符串插入整数列,你会得到一个错误,而不是一次静默的强制转换。如果你声明了外键,它就会被强制执行。如果你声明了 NOT NULL,它就真的意味着 NOT NULL。
这比它听起来应有的分量更重要。在 MySQL 里,历史上的默认是宽松的——数据库会接受有问题的数据,以后再想办法。这已经变了;现代 MySQL 的默认严格得多,你也可以配置严格程度。但文化上的继承依然存在:MySQL 有很长一段应用依赖数据库宽容的历史,也有一段很长的数据因此被悄悄搞坏的历史。
如果你想让数据库成为数据完整性的最后一道防线——而不是信任每一条应用代码路径都正确——PostgreSQL 的严格就是一种功能。那是数据库在履行它的职责。
更丰富的类型
PostgreSQL 自带一些 MySQL 要么没有、要么处理得没那么好的原生类型。最值得一提的几个:
JSONB— 带索引支持的二进制 JSON。你可以存一个文档,并用 GIN 索引深入查询它,让嵌套查找变快。MySQL 也有JSON类型,而且它能力不弱,但配上恰当索引的 PostgreSQLJSONB对文档形状的数据来说,是另一个层级的工具。- 数组 — 一个真正的数组类型,不是逗号分隔的字符串。你可以把列表存在一列里并给它建索引。
- 范围 —
int4range、tsrange之类。对预订时间窗、有效期、排期这类场景真的有用,在这些场景里"这个区间是否和那个区间重叠"是你想自然表达的一个查询。 - 几何类型和网络类型 — 点、线、多边形、
inet、cidr、macaddr。如果你的领域碰到其中任何一个,把它们做成原生类型是真正的便利。 UUID— 原生,带生成函数。
而且关键在于,PostgreSQL 允许你定义自己的类型和复合类型。如果你的数据有内置类型捕捉不到的结构,你可以把它建进 schema,而不是把它编码成字符串、再在应用里解析。
扩展
这是 PostgreSQL 最与众不同的优势。因为它是为在进程内被扩展而设计的,一整套能力生态以可加载扩展的形式生长了出来:
- PostGIS — 地理空间工作的黄金标准。如果你要认真做任何和地图、距离或地理查询相关的事,PostGIS 就是选择 Postgres 的理由,句号。
pgvector— 向量存储和相似度搜索,它已经成为 AI 和基于 embedding 的应用的基础。pg_trgm— 基于 trigram 的模糊文本匹配。hstore、uuid-ossp、pgcrypto,以及更多。
这里的模式是:数据库本身可以长出新的能力,而无需你改动架构。如果你的应用需要一种活在数据库内部的能力——这么做的应用比人们以为的要多——PostgreSQL 更有可能已经有了它,或者有一个成熟的扩展来提供它。
高级索引
两个数据库都很好地支持 B-tree 索引。PostgreSQL 走得更远。它为复合数据和全文数据提供 GIN 和 GiST 索引,为大型顺序排列表提供 BRIN 索引,还有部分索引(只索引匹配某个条件的行)、表达式索引(索引一个计算值)以及 bloom filter。你可以在一个函数上、一个 JSON 路径上,或一个行子集上建索引。
实际效果是:更多的查询形状可以被变快,而无需重构你的 schema。当你撞上性能墙时,PostgreSQL 给了你更多可以拉的杠杆,然后才需要去反规范化。
窗口函数和 CTE
两个数据库在现代版本里都支持窗口函数和公共表表达式(CTE)。PostgreSQL 的实现历史上更完整、被使用得更广,而且 Postgres 周围的文化更用力地倾向"用 SQL 表达它"。递归 CTE、LATERAL 连接和高级窗口框架,是 Postgres 用户经常伸手去用的东西。
如果你在数据库内部做大量分析——而不是导出到一个单独的数仓——这很重要。在你规模大到用不了它之前,Postgres 长期同时充当你的操作数据库和分析数据库都很舒服。
生态的广度
除了扩展之外,PostgreSQL 已经成为某类团队的默认选择:那些想把逻辑推进数据库、在乎正确性、并在把它作为一等产品提供的服务商的托管 Postgres 上构建的团队。那个社区产出了一个深厚的工具、指南和模式生态。
如果你想让数据库不只是一个笨存储——如果你想让它成为你应用逻辑的积极参与者——Postgres 就是为那种世界观而建的。
在生产环境里真正咬你的是什么
这是大多数对比文章都会跳过的一节,也是最重要的一节,因为生产环境里咬你的差异,很少是营销里的那些。
字符集与排序规则
MySQL 的字符集和排序规则的故事历史上一直是真实痛苦的来源。较老的 MySQL 版本默认用 latin1;向 utf8mb4 的过渡(让人困惑的是,它才是真正处理完整 Unicode 的编码——MySQL 的 utf8 历史上是一个不完整的实现)花了数年时间,也弄坏了不少东西。排序规则决定字符串如何排序和比较,而 MySQL 有一大堆令人困惑的排序规则,它们的名字并不总能让行为变得一目了然。
PostgreSQL 的故事更简单、更可预测。你在创建数据库时选一个编码和一个排序规则,它就行为一致。它也有自己的微妙之处——排序规则行为可能随操作系统的 locale 库而变化,这在升级时制造过意外——但它没有那么多雷区。
如果你要存储多语言的用户生成文本,这值得在你下定决心之前搞清楚。
标识符大小写与引号
MySQL 在很多平台上对标识符大小写不敏感,取决于底层文件系统,它允许你写 SELECT * FROM Users,无论表叫 users 还是 Users 都能用。PostgreSQL 把不加引号的标识符折叠成小写,所以 SELECT * FROM Users 会去找一张名为 users 的表——如果你的表实际叫 "Users"(用引号创建的),这个不加引号的查询就找不到它。
这是一个经典的迁移陷阱。对 MySQL 运行良好的代码——自由混用大小写——到了 Postgres 上就崩,因为标识符不会按开发者预期的方式解析。到处都要自律地使用小写、不加引号的标识符,但如果你在移植一个已有的应用,这一条你会切实感受到。
事务与 DDL 行为
两个数据库都支持事务。但历史上,MySQL 的存储引擎在 DDL——数据定义语言,比如 CREATE TABLE 和 ALTER TABLE——方面的行为不同:很多 DDL 语句会引发隐式提交,无法回滚。现代 MySQL(用 InnoDB)改进了事务性 DDL,但遗留行为塑造了一代迁移工具和期望。
PostgreSQL 很早就支持事务性 DDL:你可以在一个事务里运行一系列 schema 变更,如果中途某处失败,整个事情都会回滚。对迁移来说,这是一个重要的安全属性。在 Postgres 里一个失败的迁移会让你的 schema 保持原样;在较老的 MySQL 里,它可能让你迁移到一半就卡住。
如果你的部署流程把 schema 迁移作为发布的一部分来运行,就要搞清楚当迁移中途失败时,每个数据库的行为如何。这类事情是要吃过大亏才学得会的。
JSON 处理
两个数据库都支持 JSON,能力都不弱。但模型在重要方面有所不同。MySQL 的 JSON 类型以二进制格式存储 JSON,支持基于路径的查询和生成列。PostgreSQL 的 JSONB 存储一种分解后的二进制表示,直接用 GIN 支持索引,而且它的 JSON 操作符与查询规划器集成得更深。
实际差别是:在 Postgres 里,深入查询一个 JSON 列可以通过索引作为一等操作变快。在 MySQL 里,你经常最终要创建生成列并给它们建索引,这能行,但更繁琐。如果 JSON 是你数据模型的核心,这是人体工程学上一个有意义的差别。
连接上限与连接池
两个数据库的连接数都是有限的,把连接用尽都会让它们趴下。失败模式在风味上不同,但本质上一样:连接太多,你就会得到错误、延迟飙升,或者一个不再接受新客户端的数据库。
这不是选这个而非那个的理由——而是无论哪种情况都要规划连接池的理由。两个生态都有成熟的池化器,而且两者通常都部署在一个池化器后面。如果你从高并发的 serverless 环境连接,不管你选哪个数据库,你都会想要一个池化器。不要把默认连接上限当作生产设置。
升级与迁移路径
两个数据库都有被充分理解的升级路径,而且跨大版本跳跃时都需要规划。两者都不是"跑一下然后祈祷"的情况。读一读你要跨越的版本的发布说明,用你数据的副本测试升级,并为说明里警告你的事情预留时间。
两个数据库之间迁移的方向也值得想一想。从 MySQL 迁到 Postgres 是一条被踩得很熟的路,有成熟的工具和记录在案的坑——但它不是一个"点导出、点导入"的操作。类型、排序规则、大小写,以及厂商特定的 SQL 都需要关注。如果你在考虑迁移,把它当作一个项目,而不是一个任务。
对比表
这是并排对比,附带一句提醒:任何单独一行里的"胜出"很少能决定整个问题。
| 维度 | MySQL | PostgreSQL |
|---|---|---|
| 架构 | 客户端-服务器 RDBMS | 客户端-服务器 RDBMS |
| 默认姿态 | 历史上宽松,现在更严格 | 默认严格 |
| 类型系统 | 常规类型,支持 JSON | 丰富类型:JSONB、数组、范围、UUID、几何 |
| 扩展模型 | 插件系统 | 进程内扩展(PostGIS、pgvector……) |
| 索引 | B-tree、全文、空间(因引擎而异) | B-tree、GIN、GiST、BRIN、部分、表达式 |
| 窗口函数 / CTE | 支持 | 支持,广泛使用,更完整 |
| JSON | JSON 类型,生成列 | JSONB 带原生 GIN 索引 |
| 标识符大小写 | 在很多平台上不区分大小写 | 把不加引号的折叠成小写 |
| 事务性 DDL | 用 InnoDB 有所改进,历史上受限 | 长期支持 |
| 字符集 | 历史上很乱(latin1 → utf8mb4) | 更简单、一致 |
| 复制 | 内置,广泛部署 | 内置流式 + 逻辑 |
| 生态 | PHP、WordPress、共享主机、web 应用 | 分析、地理空间、注重正确性的团队 |
| 托管服务 | 到处都有 | 到处都有 |
| 工具 | 庞大、通用 | 大、成熟 |
| 最适合 | web 应用、PHP/WordPress、无处不在的托管 | 复杂数据、扩展、严格完整性 |
| Basevolt 支持 | 是 | 是 |
对那张表的诚实解读:MySQL 赢在无处不在、托管,以及和 web 的生态契合度。PostgreSQL 赢在类型丰富度、可扩展性、严格性和高级查询能力。其他一切都很接近,你的团队的熟悉度应该能决定胜负。
一个实用的决策框架
与其给你一个你会无视的流程图,不如看这些真正决定答案的问题。针对你的情况诚实地回答它们。
1. 你现有的技术栈默认用什么?
如果你在用 WordPress、Drupal、Magento,或某个生态建立在 MySQL 上的 PHP 框架,默认就是 MySQL,和它对着干会在每个项目上耗费你的时间。如果你的技术栈的工具倾向 Postgres——或者你是没有任何强牵引的绿地项目——那就倾向 Postgres。阻力最小的路是一个正当的因素,不是逃避。
2. 你需要一种活在数据库里的能力吗?
地理空间查询?AI 功能的向量搜索?带恰当索引的丰富文档查询?用窗口函数和递归 CTE 做的高级分析?如果其中任何一个答案是肯定的,那种能力大概就应该决定你的选择——而且十有八九它指向 PostgreSQL。
3. 你有多需要数据库来强制正确性?
如果你想让数据库成为数据完整性的最终权威——不管应用做什么都强制执行类型、约束和关系——PostgreSQL 的严格默认是一个有意义的优势。如果你的应用层是事实来源、数据库只是存储,MySQL 更宽容的姿态就没那么让人担心(而且现代 MySQL 反正对大多数用途已经够严格了)。
4. 谁来运维它?
如果你有一个深度了解 MySQL 的团队、却没人了解 Postgres,那就是切换的真实成本。如果你的团队对两者都自在,技术上的优点就更有分量。你的团队能自信运行、备份和调试的数据库,比一个边际的功能优势更值钱。
5. 你到底是在选择,还是在继承?
很多问这个问题的人其实是在继承一个数据库——它已经在运行、已经在生产里,问题实际上是"我该不该迁移?"迁移昂贵、有风险,而且很少仅凭功能羡慕就能被证明合理。如果 MySQL 在正常工作,你的工作负载也不需要 Postgres 独有的东西,就留下。如果你撞上了一堵只有 Postgres 能翻过的墙,那就刻意地迁移,并为它预留预算。
如果你对问题 1、4、5 回答了"MySQL",对 2 和 3 回答了"不",就用 MySQL。如果你对 2 或 3 回答了"Postgres",就用 PostgreSQL。如果确实打平了,就选你团队更懂的那个,一年后再回来看——两者都好到"错误但熟悉"的选择胜过"正确但陌生"的选择。
两个都用
很多有经验的团队实际上是这么做的:他们两个都用,而这个选择并不是互联网把它说成的非此即彼。
我见过的常见真实世界配置:
- PostgreSQL 作为主操作数据库,MySQL 用于遗留组件或 WordPress 组件。 从 WordPress 站点成长起来的公司常常为 CMS 保留 MySQL,把新服务跑在 Postgres 上。两个数据库,两份工作,一个团队。
- MySQL 用于事务型 web 应用,Postgres 用于分析。 MySQL 服务请求路径;一个副本或 ETL 管道喂给 Postgres,分析查询和像 PostGIS 或
pgvector这样的扩展住在那里。 - MySQL 用于应用,SQLite 用于本地缓存和边缘。 如果你把读取分发到边缘,你可能让 MySQL 作为事实来源,让 SQLite 副本靠近用户——这个模式我在 SQLite vs PostgreSQL 里写过。
- Postgres 用于所有新的,MySQL 用于所有旧的。 务实的避免迁移策略:不要拆掉还能用的东西,但别再往上加。
这些配置里的摩擦从来都不是数据库本身——而是工具。你最终会有一个 MySQL 的管理面板和一个完全不同的 Postgres 面板,两套连接信息,而且没办法同时看两边。开发者仅仅是在数据库工具之间切换上下文,就浪费掉惊人量的时间。
这也是我们构建 BaseVolt 让它通过同一个界面处理两个引擎的原因之一。把它指向一个 MySQL 连接或一个 Postgres 连接,无论哪种你都会得到相同的管理面板——网格、画廊、看板和 dashboard 视图、关系可视化,以及不改动你 schema 的行内编辑。对同时跑两者的团队,这意味着一个工具而不是两个,以及在你试图理解数据时只需看一个地方。
如果你在专门为其中一个引擎权衡管理工具,我另外写过 MySQL 管理工具对比,而如果你是从一个通用客户端过来的,值得了解一下继续用 DBeaver 或 TablePlus 相比一个专门构建的面板,你会放弃什么。
常见错误
一个简短的清单,来自我看过的那些出问题的事。
为一个 WordPress 项目选 Postgres。 你会把整个项目花在和一个假定 MySQL 的生态对着干上。用 MySQL,或者明知代价地接受这笔税。
为一个需要 PostGIS 或 pgvector 的工作负载选 MySQL。 如果那种能力是你产品的核心,别试图用 MySQL 里的变通办法来假冒它。选拥有那个工具的数据库。
因为 Postgres "更好"而迁移。 功能羡慕不是迁移计划。当你撞上一堵具体的墙时再迁移,并为它实际所需的项目量预留预算。
假定 MySQL 宽松的默认值还是默认值。 现代 MySQL 比它的名声严格得多。检查你的实际配置,而不是重复 2012 年的建议。
把任一数据库的默认连接上限当作生产就绪。 两者在真实负载下都需要连接池。这不是一个区分点——而是一个共同的坑。
根据你在网上找到的基准测试做选择。 基准测试测量的是基准测试的工作负载,不是你的。你的 schema、索引和访问模式才是主导。
直到迁移那天才理会大小写和排序规则的差异。 如果你将来有可能在两者之间移动,现在就写小写、不加引号的标识符,并想想编码。现在做是免费的,事后修是昂贵的。
结论
MySQL 和 PostgreSQL 都很出色、都很成熟,也都能在 2026 年运行严肃的生产系统。真正重要的差异比争论暗示的要窄,而争论通常是被那个人用得更多的那个所驱动的。
简短版:
- MySQL:当你身处 PHP/WordPress/web 托管的世界,当无处不在和生态契合度重要,当你想在传统的读多 web 工作负载上走阻力最小的路,以及当你的团队很懂它时。
- PostgreSQL:当你需要更丰富的类型、像 PostGIS 或
pgvector这样的扩展、在数据库层强制执行的严格完整性、高级索引,或依赖窗口函数和 CTE 的分析时。
这两个清单都不是"正确答案"。它们是对不同问题的不同答案,而真正的技能是知道你到底在问哪个问题。
而对很多团队来说,诚实的答案是你会最终两个都有——MySQL 用在生态牵引你的地方,Postgres 用在能力牵引你的地方——这正是为什么一个两者都懂的管理面板值得拥有。BaseVolt 直接连接 PostgreSQL、MySQL、SQLite 和 Cloudflare D1,完全在你的机器上运行,并把你的凭据留在本地。demo.basevolt.app 有在线演示,或者试试免费档——两个数据源,无需账号。
在用 MySQL 或 Postgres 做东西?我很好奇你选了哪个、是什么让它倾斜——在 X 上找我。