很多人在给项目选数据库时都会卡在同一个问题上:到底用 MySQL 还是 PostgreSQL?网上常见的回答要么是"都行",要么是一句"PostgreSQL 更强大"。但"更强大"到底体现在哪里、你的业务是不是用得上、用了之后服务器配置要付出什么代价,这些具体的东西反而没人讲清楚。
这篇文章不打算做无意义的口水战,而是把两者的差异落到六个可验证的维度上:事务与隔离级别、数据类型(JSON 与数组)、扩展能力、复制机制、全文检索、性能特征,再补上许可与生态。每一节都给出可执行的验证命令,最后给一张选型对照表和"什么业务选哪个"的结论。
一、先给结论:它不是"谁替换谁"的问题
MySQL 和 PostgreSQL 都是关系型数据库,都支持 SQL 标准、都支持事务、都有成熟的复制和备份方案。它们的分水岭不在"能不能做",而在"做起来顺不顺手、代价高不高"。
一个粗略的经验判断:如果你的业务是典型的 OLTP —— 用户、订单、商品、日志表这类结构相对固定、读多写多、追求简单和高并发点查的业务,MySQL 的生态、资料、运维人才储备更丰富;如果你的业务涉及复杂查询、地理空间、JSON 半结构化数据、自定义类型、窗口函数、CTE 递归,或者你希望数据库能承担更多"计算"职责,PostgreSQL 通常更省事。
但这句话不是绝对的。下面逐项拆开,你看完自然能对号入座。
二、事务与隔离级别
两者都支持 ACID 事务,区别在于默认隔离级别和实现方式。
MySQL 的 InnoDB 默认隔离级别是 REPEATABLE READ(可重复读),PostgreSQL 默认是 READ COMMITTED(读已提交)。这个差异经常被忽视,却直接影响业务代码的行为。
在 MySQL 的可重复读下,事务开始后读到的数据快照在整个事务期间不变,而且 MySQL 用间隙锁(gap lock)来防止幻读,这在大量并发写入时可能带来更多锁等待,甚至死锁。PostgreSQL 的读已提交下,每条语句看到的是语句开始时的快照,同一条查询在事务里执行两次可能结果不同。如果你的代码依赖"事务内多次读结果一致",在 PostgreSQL 里需要显式使用 REPEATABLE READ。
验证当前隔离级别:
-- MySQL
SELECT @@transaction_isolation; -- MySQL 8.0,旧版本用 @@tx_isolation
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- PostgreSQL
SHOW transaction_isolation;
SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL REPEATABLE READ;
PostgreSQL 还有一个 MySQL 长期缺失的能力:DDL 事务。在 PostgreSQL 里你可以把建表、改表、加索引放进一个事务,出错整体回滚。MySQL 的 DDL 是隐式提交的,一旦执行就无法回滚,这在做结构变更时风险更高。所以大规模的 schema 变更,PostgreSQL 在回滚能力上更让人安心。
三、数据类型:JSON 与数组是最大分水岭
数据类型是两者差异最直观的地方。
MySQL 从 5.7 起支持 JSON 类型,8.0 增加了 JSON 函数和部分索引能力,但 JSON 本质上是"存得住、查得动",离真正的文档型操作还有距离。PostgreSQL 的 JSONB 是二进制存储、支持 GIN 索引,可以直接对 JSON 内部字段建索引、做包含查询,操作体验接近文档数据库。此外 PostgreSQL 原生支持数组类型、范围类型、枚举、复合类型、hstore,MySQL 在这些方面要么没有,要么功能有限。
对比一下 JSON 查询:
-- MySQL 8.0
SELECT * FROM orders WHERE JSON_EXTRACT(payload, '$.user_id') = 1001;
-- 或用 ->> 语法
SELECT * FROM orders WHERE payload->>'$.user_id' = '1001';
-- PostgreSQL,JSONB 建 GIN 索引后性能更好
CREATE INDEX idx_orders_payload ON orders USING GIN (payload);
SELECT * FROM orders WHERE payload @> '{"user_id": 1001}';
PostgreSQL 的数组类型在处理标签、多值属性时也很方便:
-- PostgreSQL:tags 是 text[] 类型,直接建索引并包含查询
CREATE INDEX idx_tags ON articles USING GIN (tags);
SELECT * FROM articles WHERE tags @> ARRAY['mysql'];
如果你的业务里"半结构化数据"占比高(用户自定义字段、埋点、配置、标签体系),PostgreSQL 的 JSONB 往往能省掉一层 Elasticsearch 或 MongoDB。反过来,如果你的数据模型非常规整,这个优势就用不上。
四、扩展能力与生态
PostgreSQL 有"世界上最先进的开源关系数据库"这个自我定位,核心底气之一就是扩展机制。你可以用 CREATE EXTENSION 加载社区扩展,把数据库的能力直接拉高一个档次:
- PostGIS:地理空间计算的事实标准,定位、距离、区域判断都能在数据库里做。
- pg_trgm:三元组相似度,做模糊搜索和 LIKE 加速。
- timescaledb:时序数据的分区、压缩、连续聚合。
- pg_stat_statements:SQL 级别的性能统计,是排查问题的必备工具。
CREATE EXTENSION IF NOT EXISTS postgis;
CREATE EXTENSION IF NOT EXISTS pg_trgm;
SELECT * FROM pg_available_extensions ORDER BY name; -- 查看可用扩展
MySQL 的扩展更多体现在存储引擎和插件层面(如 InnoDB、MyISAM、以及云厂商的专有引擎),但这种"外挂式"的扩展不如 PostgreSQL 灵活。MySQL 的优势在于生态广度:几乎所有编程语言、几乎所有 ORM、几乎所有云厂商都对 MySQL 有一等公民支持,中文社区的教程、踩坑记录、招聘需求也更多。这意味着出问题时更容易找到人帮忙,团队上手成本更低。
五、复制机制
两者的复制模型差异很大。
MySQL 主从复制基于 binlog,默认是异步复制,从库通过 IO 线程拉取 binlog、SQL 线程回放。MySQL 5.7 之后支持并行复制(基于组提交或逻辑时钟),MySQL 8.0 进一步支持基于 WRITESET 的并行复制,能显著降低主从延迟。半同步复制(semi-sync)可以保证至少一个从库收到日志再返回,是有损一致性下的折中。
PostgreSQL 的复制基于 WAL(Write-Ahead Log),分物理复制和逻辑复制。物理复制是流复制(streaming replication),从库实时接收 WAL,延迟通常比 MySQL 异步复制更低;而且 PostgreSQL 的同步复制可以配置 synchronous_commit,灵活控制一致性级别。逻辑复制则适合按表同步、跨版本升级等场景。
-- MySQL 查看复制状态
SHOW SLAVE STATUS\G -- 8.0.22 起建议用 SHOW REPLICA STATUS
-- PostgreSQL 查看复制状态(在从库)
SELECT * FROM pg_stat_wal_receiver;
-- 在主库查看连接过来的从库
SELECT * FROM pg_stat_replication;
从一致性角度看,PostgreSQL 的流复制在低延迟场景更占优,MySQL 的并行复制在写入密集场景表现越来越好。这里没有绝对赢家,取决于你的读写压力形态。
六、全文检索
两者都把全文检索做进了数据库内核,但能力档次不同。
MySQL 的全文索引(FULLTEXT)支持 MyISAM 和 InnoDB,能处理英文分词,中文分词需要借助 ngram 解析器,效果一般,通常只适合轻量场景,真正做搜索还是得上 Elasticsearch。
PostgreSQL 的 tsvector / tsquery 功能更完整,支持词干提取、权重、排名、多语言配置,配合 pg_trgm 可以做模糊匹配,配合 GIN 索引性能不错。对于中小规模的站内搜索,PostgreSQL 常常能顶住,不必专门引入搜索引擎。
-- PostgreSQL 全文检索
SELECT title, ts_rank(to_tsvector('simple', title), q) AS rank
FROM articles, to_tsquery('simple', 'mysql & 复制') q
WHERE to_tsvector('simple', title) @@ q
ORDER BY rank DESC LIMIT 10;
七、性能特征对比
性能不能脱离场景谈,但可以给出一些方向性结论。
| 维度 | MySQL(InnoDB) | PostgreSQL |
|---|---|---|
| 简单主键点查 | 极快,缓冲池效率高 | 快,但多版本(MVCC)有额外开销 |
| 高并发短事务 | 表现成熟稳定 | 良好,但长连接下的 MVCC 膨胀需关注 |
| 复杂查询/多表 JOIN | 优化器相对保守 | 优化器更强,复杂查询通常更快 |
| 大批量写入 | 成熟,参数易调 | 良好,但 autovacuum 需合理配置 |
| 大对象/半结构化 | 一般 | JSONB、数组优势明显 |
| 资源占用 | 相对轻 | 相对重,连接数多时内存压力大 |
一个常被提及的差异是 MVCC 的实现:MySQL 用 undo log 保存旧版本,旧数据清理相对自动;PostgreSQL 直接在数据页里保留多版本,需要 VACUUM 清理死元组,如果 autovacuum 配置不当,表会膨胀(bloat),查询变慢、磁盘占用上升。所以 PostgreSQL 运维里,"监控表膨胀、调 autovacuum"是必修课,MySQL 里则相对轻松。
另外 PostgreSQL 是进程模型,每个连接对应一个后端进程,连接数上千时进程切换和内存开销明显,因此 PostgreSQL 更依赖连接池(如 PgBouncer)。MySQL 是线程模型,单机连接数上限通常更高(常配到 500 到 1000 乃至更多)。
八、许可与生态
MySQL 采用 GPL v2 许可,社区版由 Oracle 维护,另有商业版和企业版;历史上还分化出 MariaDB(由原 MySQL 作者主导,采用 GPL,兼容性较好,很多发行版默认提供)。选 MySQL 时要留意"用哪个分支",MariaDB 和 MySQL 在部分特性上已有分歧。
PostgreSQL 采用类似 MIT/BSD 的宽松许可(PostgreSQL License),允许自由使用和修改,对商业闭源集成友好,没有许可证上的顾虑。这一点的实际影响在于:如果你要把数据库嵌进商业产品分发,PostgreSQL 的许可更省心。
生态方面,MySQL 在互联网公司、特别是早期 LAMP 架构和大量 SaaS 里是主流,运维资料丰富;PostgreSQL 在金融、地理信息、数据分析、以及追求"用一个数据库解决更多问题"的团队里增长迅速,近年在 DB-Engines 等排行榜上的热度持续上升。
九、服务器配置差异
选型之后,服务器配置思路也不同。
MySQL 的关键参数通常是 innodb_buffer_pool_size(建议设为物理内存的 50% 到 70%)、max_connections、innodb_log_file_size。单机内存 16GB 的小型 MySQL,缓冲池配 8GB 到 10GB 是常见做法。
PostgreSQL 的关键参数是 shared_buffers(经验值约为物理内存的 25%,因为还要靠操作系统页缓存)、work_mem(注意是每个排序/哈希操作可用,不是全局)、effective_cache_size、max_connections。PostgreSQL 的 shared_buffers 不宜设太大,超过内存 40% 往往收益递减。
# my.cnf(MySQL)示例,8 核 16G 机器
[mysqld]
innodb_buffer_pool_size = 10G
max_connections = 500
innodb_log_file_size = 1G
# postgresql.conf(PostgreSQL)示例,8 核 16G 机器
shared_buffers = 4GB
effective_cache_size = 12GB
work_mem = 8MB
maintenance_work_mem = 512MB
max_connections = 200
差距很明显:MySQL 敢把一半以上内存给缓冲池,PostgreSQL 只给四分之一,剩下的交给操作系统。这也意味着同样物理内存,PostgreSQL 的连接数容量更受限制,超配连接容易触发内存不足。
十、选型对照表与结论
把上面的内容浓缩成一张表:
| 场景 | 推荐 | 理由 |
|---|---|---|
| 典型 OLTP(用户/订单/商品) | MySQL | 生态成熟、运维资料多、缓冲池高效 |
| 复杂查询、报表、分析 | PostgreSQL | 优化器更强、窗口函数/CTE 完善 |
| 半结构化数据、JSON 多 | PostgreSQL | JSONB + GIN 索引体验接近文档库 |
| 地理空间应用 | PostgreSQL | PostGIS 是事实标准 |
| 需要数据库内做全文检索 | PostgreSQL | tsvector 能力更完整 |
| 团队熟悉 MySQL 且要招人易 | MySQL | 人才与社区储备更广 |
| 需要嵌进商业闭源产品 | PostgreSQL | 许可更宽松 |
| 极高连接数、单机实例 | MySQL | 线程模型、连接上限更高 |
回到最初的问题:什么业务选哪个?
- 电商、内容站、传统业务系统,团队规模中小、追求稳妥和易招人 —— 选 MySQL。
- 数据模型复杂、有地理/JSON/搜索需求、追求"少引入中间件" —— 选 PostgreSQL。
- 你已经有明确的技术栈和运维经验,不要为了"更先进"强行换,迁移成本往往大于收益。
- 新项目如果没有历史包袱,且团队愿意学,PostgreSQL 的长期扩展性通常更好。
常见问题
Q:PostgreSQL 比 MySQL 慢吗?
不能一概而论。简单点查 MySQL 往往更快,复杂查询 PostgreSQL 通常更强。真正的瓶颈多数出现在索引设计、SQL 写法、硬件配置上,而不是数据库品牌。
Q:MySQL 可以换成 PostgreSQL 吗?
技术上可以,但成本不小:SQL 方言、数据类型、自增主键、日期函数、分页语法都有差异,ORM 可能也需要调整。建议新项目决策,老项目慎迁。
Q:MariaDB 和 MySQL 怎么选?
MariaDB 兼容 MySQL,加了部分新特性,很多发行版默认装它。如果依赖特定 MySQL 8.0 特性或云厂商的托管 MySQL,优先 MySQL;追求开源纯粹性可考虑 MariaDB。
Q:两者能同时用吗?
可以,而且很常见。比如用 MySQL 跑交易库、PostgreSQL 跑分析库或地理库,各取所长。代价是运维两套系统,小团队要权衡。
Q:只看性能,怎么快速验证哪个适合我?
用你的真实数据和真实 SQL 各建一次库,灌入相同数据,跑相同查询做压测(如 sysbench、pgbench),指标以真实业务为准,别看跑分榜单。
总结
- MySQL 与 PostgreSQL 不是替代关系,而是各有强项:一个胜在生态与 OLTP 稳妥,一个胜在查询能力与数据类型丰富。
- 最直观的分水岭是 JSONB、数组、PostGIS 这类扩展能力,业务涉及半结构化或地理数据时 PostgreSQL 明显省事。
- 事务上注意默认隔离级别差异(MySQL 可重复读 vs PostgreSQL 读已提交),以及 PostgreSQL 支持 DDL 事务、MySQL 的 DDL 不可回滚。
- 配置上 MySQL 敢给缓冲池一半以上内存,PostgreSQL 只给约四分之一,连接数容量因此更受限,需要连接池配合。
- 选型最终看三点:业务数据形态、团队经验、长期运维成本。没有万能答案,只有是否匹配。
企业QQ咨询




