首页
学习
活动
专区
圈层
工具
发布

为什么高性能场景选用Postgres SQL 而不是 MySQL

我昨天下班路上,地铁里还在刷手机,看到有人问“为什么搞高性能的业务,很多人会选 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 更像“能上赛道的工程车”。当然选型也得看团队熟悉度和成本,不然再强大你不会用,也白搭。

  • 发表于:
  • 原文链接https://page.om.qq.com/page/O3krzSRU34HvUBnoG7Ay1bJw0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。
领券