我昨天下班路上,地铁里还在刷手机,看到有人问“为什么搞高性能的业务,很多人会选 PostgreSQL 而不是 MySQL”,我一下就来了劲儿。正好我们组最近也在讨论数据库选型,这话题我还挺有发言权的。今天就跟你聊聊,口语化一点,不整那些过于夸张的说法,就像咱们平时坐下来闲聊技术一样。
先说说两者定位
MySQL 你肯定用过吧,毕竟互联网公司大部分 CRUD 项目都是它撑起来的。简单、够用、生态庞大,能跑就行。但要是真到那种高并发、复杂查询、大数据量 OLTP(联机事务处理)的场景,它就有点力不从心了。Postgres(全名 PostgreSQL)呢,本身就是号称“世界上最先进的开源数据库”,这口号虽然有点硬,但核心确实厉害,它从一开始就是面向标准化、事务完整性和复杂场景优化设计的。
事务与一致性
Postgres 在事务和一致性这块,比 MySQL 的 InnoDB 更细腻。比如它的MVCC(多版本并发控制),是真的天然支持,不像 MySQL 那样要靠 undo log 去模拟。Postgres 里每个事务看到的世界都是一致的,不会出现“脏读半天才发现有锁”的情况。而且它支持可序列化事务隔离级别,而且是真正的序列化实现,MySQL 的那个 SERIALIZABLE 说白了还是乐观锁+冲突回滚。
用 Java 写点伪代码感受下,假如两个事务并发更新同一行:
// 事务A
Connection connA = dataSource.getConnection();
connA.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
connA.prepareStatement("UPDATE account SET balance = balance - 100 WHERE id = 1").executeUpdate();
// 事务B
Connection connB = dataSource.getConnection();
connB.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
connB.prepareStatement("UPDATE account SET balance = balance - 200 WHERE id = 1").executeUpdate();
在 Postgres 下,这种场景保证要么 A 提交成功 B 回滚,要么反过来,不会出现两个事务都扣钱导致余额错误。而在 MySQL,有些隔离级别下你就得额外加行级锁或乐观版本号去兜底。
索引与查询优化
说到索引,MySQL 的主力是 B+Tree,偶尔有哈希索引,但场景很局限。Postgres 就花活多了:B-Tree、Hash、GIN、GiST、BRIN……各种索引适配不同的查询模式,尤其是全文搜索,MySQL 那个 fulltext 基本没人敢真用,Postgres 的 GIN 索引却是 Elasticsearch 之外一个很硬核的替代方案。你要做 JSONB 字段的查询,用 GIN 甚至能几百万行秒出结果。
举个 SQL:
-- JSONB 字段建索引
CREATE INDEX idx_data_jsonb ON logs USING gin (data);
-- 查询某个字段是否包含特定 key
SELECT * FROM logs WHERE data @> '{"userId": 12345}';
这在 MySQL 里写 JSON 查询就别提了,不仅语法丑,性能还差得一批。
并行查询和扩展能力
再说并行,MySQL 直到最近版本才开始玩点并行执行,还很鸡肋。Postgres 很早就有并行查询执行计划,复杂 SQL 可以自动拆分子任务多核跑,你在分析类场景下能直接感受到提速。别小看这一点,数据一旦上了亿级,没有并行就是灾难。
还有扩展能力,Postgres 天然支持插件机制,你可以加上时序数据库扩展(TimescaleDB)、地理空间扩展(PostGIS)、甚至写个自己的数据类型。MySQL 就是比较死板,最多是搞个插件式存储引擎,但对开发者暴露不多。
写扩展的例子
比如我们想给 Java 里插入 UUID 自动转为数据库的 uuid 类型,Postgres 直接原生支持:
PreparedStatement ps = conn.prepareStatement("INSERT INTO orders (id, info) VALUES (?, ?)");
ps.setObject(1, UUID.randomUUID()); // 直接塞进 uuid 列
ps.setString(2, "测试数据");
ps.executeUpdate();
而在 MySQL,UUID 就只能当字符串存,索引效果贼差。
高可用与复制
有人可能会说,MySQL 有主从复制啊,延迟也能接受。但真到金融、电商这些要保证一致性的地方,Postgres 的流复制+逻辑复制更稳。它可以做到毫秒级延迟,还能按表、按行逻辑同步,做数据迁移非常丝滑。而且生态里像 Patroni、Pgpool-II 这种高可用组件成熟度也高。MySQL 之前那个半同步复制,真要切主的时候心惊胆战。
开发体验与标准兼容
还有一点容易被忽略:标准兼容性。Postgres 对 SQL 标准支持度非常高,比如窗口函数、CTE、递归查询,这些 MySQL 不是没有,但要么实现残缺,要么延迟很多版本才补齐。你写复杂报表的时候,用 Postgres 的语法可以少绕不少弯子。
比如递归查询树形结构:
WITH RECURSIVE subordinates AS (
SELECT id, name, manager_id
FROM employees
WHERE id = 1
UNION ALL
SELECT e.id, e.name, e.manager_id
FROM employees e
INNER JOIN subordinates s ON e.manager_id = s.id
)
SELECT * FROM subordinates;
这个在 MySQL 里?很久才支持 CTE,而且性能不如人意。
什么时候 MySQL 依旧合适
当然也不是说 MySQL 一无是处。你要是就是做个小系统,简单 CRUD,多数查询靠主键,团队也全是 MySQL 背景,那 MySQL 完全够用。而且 MySQL 在读多写少的互联网场景,配合中间件(像 ShardingSphere、MyCat)也能跑得飞起。但要是那种要复杂事务、要大数据一致性、要灵活查询扩展的高性能业务,Postgres 会更合适。
回过头来看,为什么高性能场景会选 Postgres?说白了就是:它的事务更严谨,查询更灵活,扩展性更强,标准更贴合,架构也更现代。MySQL 更像是“简单好用的家用车”,Postgres 更像“能上赛道的工程车”。当然选型也得看团队熟悉度和成本,不然再强大你不会用,也白搭。