读写混合TPS差六倍,PostgreSQL与MySQL架构差异实测

简介: 从架构设计、索引实现、事务隔离、复制机制、运维体验五个维度深度对比PostgreSQL与MySQL,覆盖MySQL 9.0向量检索与PostgreSQL 17新特性,附权威基准数据和选型决策框架

大家好,我是数据库小学妹👋我踩过的坑,你别再踩。

“PostgreSQL vs MySQL,2026年到底该学哪个?”这个问题我回答过不下20遍。以我个人来说,转行时先学的MySQL,后来在生产环境同时维护MySQL和PG两套系统,两边的坑都踩过。今天把真实对比写出来,不站队,只讲技术差异和适用场景,希望能给迷茫的你一点思路,少走弯路少踩坑。

先交代版本背景。MySQL 8.0已经在2026年4月结束生命周期,9.0已发布,引入原生VECTOR向量类型和向量检索,9.7.0 LTS是下一代长期支持版。PG这边主流是17.x。下面的对比以这两个最新版本为准。

架构设计的根本分歧

MySQL和PG最大的区别不在SQL语法,在架构哲学。MySQL是多引擎架构,核心是Server层加存储引擎层,Server层处理连接、解析、优化,存储引擎负责数据存储和事务。InnoDB是最常用的引擎,但你也可以换成MyISAM、Memory、TokuDB。PG是单引擎架构,整个数据库是一个统一系统,存储引擎就是内核本身,你不能换引擎,但可以扩展类型系统、加索引类型、写自定义函数。

MySQL架构:
Client → Server层(解析/优化) → InnoDB引擎(存储/事务)

PG架构:
Client → 内核(解析/优化/存储/事务一体化)

这个差异决定了后续所有不同。还有一个连带差异在连接模型上:MySQL默认一个连接一个线程,线程轻量但共享进程内存;PG一个连接一个进程,进程隔离更彻底,但连接开销大,高并发下通常要靠连接池顶住。

索引实现:MySQL的B+Tree vs PG的多索引类型

MySQL InnoDB只有一种主索引B+Tree,所有查询优化都围绕它展开。PG支持六种索引类型,每种针对不同场景。

索引类型 适用场景 查询算子
B-Tree 等值、范围、排序 = > < >= <= BETWEEN
Hash 纯等值查询 =
GiST 范围类型、几何数据 自定义
GIN 全文检索、数组、JSONB @> &&
SP-GiST 空间分区树 自定义
BRIN 超大表块级索引 范围过滤

生产环境最常用的是B-Tree和GIN。GIN是PG的杀手级特性,本质是倒排索引,JSONB字段用它就能高效查询嵌套文档的任意路径。

-- PG: JSONB GIN索引
CREATE INDEX idx_user_profile ON t_user USING GIN(profile);

-- 高效查询嵌套字段
SELECT * FROM t_user
WHERE profile @> '{"vip": true, "level": 3}';

MySQL 8.0也支持JSON,但查询嵌套字段主要靠生成列加索引,8.0.17后才多了多值索引支持JSON数组,整体灵活性和效率还是比PG的GIN差一个量级。

一个真实的性能差距

同样一个用户画像表,五百万行,每个用户三十个标签,按标签组合查询。同样的查询,PG用JSONB+GIN索引,MySQL用生成列加B+Tree,复杂嵌套查询上PG明显更快,响应差距肉眼可见。具体差多少倍我不敢给你精确数字,这个受表结构、数据分布、硬件影响太大。更宏观的性能面,2026年3月的权威OLTP基准里,PostgreSQL 17.9在读写混合TPS上约是MySQL 8.4.8的六倍多,点查QPS也领先,MySQL只在纯读点查上略占优。

事务隔离:RR和RC的不同实现

两个数据库都支持四种隔离级别,但默认级别不同:MySQL默认Repeatable Read,PG默认Read Committed。这不是随意选的,是MVCC实现方式不同决定的。

MySQL的MVCC:基于undo log

MySQL的InnoDB在更新数据时,原值写入undo log,新值写入数据页。读操作读的是数据页加undo log重建的快照版本,每个事务有自己的读视图。RR级别下同一个事务内的多次读取看到同一个快照,天然解决不可重复读,再加上Next-Key Lock,绝大多数场景也杜绝了幻读。它和PG的区别只是实现方式不同:MySQL靠加锁,PG靠快照,不是说MySQL的RR有功能缺陷。

PG的MVCC:基于多版本行

PG的更新不修改原行,而是写入新行,旧行标记为过期。读操作直接读数据页里的可见版本,不需要undo log。RC级别下每次SELECT看到查询开始时的最新快照,同一个事务内两次SELECT可能看到不同结果。所以PG的默认RC比MySQL的RR弱一级,但并发性能更好。

隔离级别对比

隔离级别 MySQL PG
Read Uncommitted 支持 支持(等同于RC)
Read Committed 支持 默认
Repeatable Read 默认 支持
Serializable 支持 支持(SSI)

这张表容易让人误会,其实两个数据库都完整支持所有四种隔离级别,区别只是默认值不同:MySQL默认RR,PG默认RC。

PG的Serializable用的是SSI可串行化隔离,比MySQL的snapshot serializable更强,能检测到写偏斜这类真正的序列化冲突。但SSI的性能开销很大,生产环境很少真正用它。

选型建议

读多写少、一致性要求高的场景,MySQL的RR默认级别开箱即用。高并发写入、读一致性要求不极端的场景,PG的RC默认性能更好。金融级强一致场景,PG的SSI更可靠,但性能开销大,实际业务里很少用。

复制机制:binlog+SQL线程 vs 流复制WAL

MySQL的主从复制是异步的,主库写binlog,从库的IO线程拉取binlog写到relay log,SQL线程重放relay log。

Master → binlog → Slave IO Thread → relay log → Slave SQL Thread → 重放

延迟是MySQL主从的固有缺陷,大事务、DDL、单线程重放都会导致延迟。8.0引入了并行复制,早期并行度受限于跨库事务,8.0.26后引入了基于WRITESET的并行复制,并行度不再只限于跨库,实际效果取决于配置。

PG的流复制更底层,主库写WAL预写日志,从库直接通过网络接收WAL流,在存储引擎层重放。从库可以设为热备模式,重放的同时接受只读查询。PG 17还新增了从备库进行逻辑复制的能力和pg_wait_until_replay_caughtup()函数,逻辑复制进一步增强。

Primary → WAL Sender → WAL Stream → Standby WAL Receiver → 引擎层重放

延迟对比

MySQL主从延迟在生产环境常见3到10秒,大事务场景可能到分钟级。PG流复制延迟通常在毫秒级,同城部署基本感知不到。

故障切换

MySQL需要第三方工具,MHA、Orchestrator、MGR。PG自身不带自动故障切换,通常用repmgr、Patroni或pg_auto_failover来做,Patroni基于etcd或ZooKeeper做选主,是目前的主流选择。但生态成熟度上,MySQL的高可用方案更丰富,ProxySQL、MHA、Orchestrator都有大量生产验证。

运维体验:谁让你少加班

这部分是纯个人感受,两个库我都维护过生产环境。

日常操作对比

操作 MySQL PG
安装 yum/apt一条命令 官方源配置稍复杂
客户端 mysql命令行 psql功能更强
查看连接 SHOW PROCESSLIST pg_stat_activity视图
分析查询 EXPLAIN EXPLAIN ANALYZE BUFFERS
备份 mysqldump / xtrabackup pg_dump / pg_basebackup
在线DDL 加列等走INSTANT秒完成,改类型仍需pt-osc/gh-ost 多数DDL不阻塞读写
VACUUM 不需要 必须配置自动VACUUM

补充一句在线DDL:MySQL 8.0的INSTANT加列不是万能的,行格式为COMPRESSED的表、部分字段类型都有限制,不是所有加列都能走INSTANT。

PG的EXPLAIN ANALYZE BUFFERS是我最喜欢的功能,直接显示实际执行时间、实际扫描行数、buffer命中情况。MySQL的EXPLAIN默认只有估算值,不过8.0也支持EXPLAIN ANALYZE,能看实际执行时间和行数,只是不如PG的EXPLAIN (ANALYZE, BUFFERS)详细。

-- PG: 真实的执行统计
EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)
SELECT * FROM t_user WHERE status = 1;

-- 输出包含:
-- 实际执行时间: 12.345ms
-- 实际行数: 5230
-- Buffer命中: shared hit=1024 read=38
-- MySQL: 只有估算值
EXPLAIN SELECT * FROM t_user WHERE status = 1;
-- rows列是优化器估算值,可能与实际差几倍

VACUUM问题

PG的UPDATE不删除原行,旧行标记为死行,长期不VACUUM表会膨胀。我遇到过一张表,实际数据五万行,死行五十万行,表文件占了8G。

-- PG: 查看死行
SELECT relname, n_live_tup, n_dead_tup,
  ROUND(n_dead_tup::numeric / NULLIF(n_live_tup, 0) * 100, 1) AS dead_pct
FROM pg_stat_user_tables
WHERE n_dead_tup > 0
ORDER BY n_dead_tup DESC;

自动VACUUM必须开,但默认阈值对大表不够激进。好消息是PG 17在VACUUM上有明显改进,内存消耗降低,高并发写入性能翻倍,老版本需要更激进调参,17之后默认行为已经好很多。

# postgresql.conf
autovacuum = on
# 默认20%,对大表太宽松
autovacuum_vacuum_scale_factor = 0.05
# 对热点表单独设
ALTER TABLE t_user SET (autovacuum_vacuum_scale_factor = 0.01);

MySQL不需要操心这个问题,InnoDB的MVCC基于undo log,没有死行概念。

扩展性

PG的类型系统和函数系统远超MySQL,自定义类型、数组类型、范围类型、复合类型都有。扩展生态也很强,pgvector做向量检索,PostGIS做地理信息,timescaledb做时序数据。MySQL的扩展点主要在存储引擎层,用户侧能做的扩展有限,不过这个短板正在补,MySQL 9.0已经内置原生VECTOR向量类型和向量检索,虽然还在早期阶段。

生态和社区

MySQL的生态优势在于规模,互联网公司用MySQL的最多,招聘市场上MySQL DBA岗位是PG的五倍以上,教程、工具、第三方服务都是MySQL优先。PG的优势在于技术深度,复杂查询、GIS、数据分析、JSON处理领先,开发者社区对PG的评价普遍更高。

我团队里三个DBA,两个MySQL熟,一个PG熟。MySQL出线上问题,随便一个DBA都能处理;PG出了问题,只有那个PG熟的人能搞定。这就是MySQL生态优势的现实体现。

选型决策框架

最后给一个实用的决策路径。互联网业务后端,高并发读写、简单查询为主、团队MySQL经验多,选MySQL。复杂查询、GIS、JSON处理、数据分析,需要强一致性和高级类型,选PG。传统企业转型,已有Oracle系统要迁移,需要存储过程和复杂业务逻辑,PG兼容性更好。如果两个都要,读写分离架构里MySQL做写入、PG做分析,也是常见方案。

避坑清单

PG的UPDATE不删除旧行,而是写入新行、把旧行标记为死行,长期不VACUUM表文件会严重膨胀。我遇到过一张表,实际数据五万行、死行五十万行,表文件占了8G。autovacuum必须开,但默认20%的阈值对大表太宽松,要调低scale_factor,热点表单独设更小的值。

MySQL默认EXPLAIN里的rows列是优化器估算值,可能和实际差几倍,别拿它当真。8.0虽然支持EXPLAIN ANALYZE,但调优还是要结合慢日志里的实际扫描行数和执行时间验证,判断走没走索引最终还是要实测。

PG的work_mem是每个排序、哈希操作单独分配的内存上限,不是全局共享。连接数多时,真实内存消耗是连接数乘以work_mem,几百个连接可能直接把内存打爆。OLAP场景想调大work_mem避免落盘,得先盯住连接池规模。

两个数据库的分页都用LIMIT/OFFSET,深分页性能都差,因为要扫描前面所有行再丢弃。百万级偏移别再用OFFSET,改成游标分页,用上一页最后一条的主键当游标继续往后查。

总结

MySQL和PG没有绝对的谁更好,只有谁更适合。MySQL赢在生态规模、开箱即用和运维人才储备,PG赢在技术深度、类型系统和一致性能力。如果团队以MySQL为主,别急着全面上PG,先把JSON、复杂查询这类场景单独拆出去试;如果团队已经是PG,就发挥它的一致性优势,把SSI和高级类型用起来。选型最怕的是用A的思维硬套B。

我是数据库小学妹,帮你少走弯路少踩坑,咱们下篇见👋

相关文章
|
29天前
|
安全 关系型数据库 MySQL
切换从32秒缩到10秒,MHA到InnoDB Cluster升级复盘
从MHA停维护近十年、份额跌至12%的现实切入,完整记录从MHA一主两从升级到InnoDB Cluster的路径,含MySQL Shell建集群、Router切换、数据迁移与验证下线
|
1月前
|
SQL 关系型数据库 MySQL
误UPDATE清零十万条余额,47分钟靠binlog全量救回
从一次误UPDATE全表清零余额的事故切入,解析binlog ROW格式的恢复原理,附mysqlbinlog精确时间点提取脚本,以及my2sql、lightning等8.0可用闪回工具的实战用法
|
1月前
|
缓存 监控 NoSQL
命中率98%跌至23%,17条告警齐发:Redis缓存三大故障复盘
从618促销缓存雪崩事故切入,深度解析缓存穿透、击穿、雪崩的底层机制、生产级防御方案与监控告警策略,附布隆过滤器实现和分布式锁代码
|
1月前
|
存储 搜索推荐 关系型数据库
纯向量库架构上线两周出事故,我帮他们重构后发现了3个选型误区
从一次生产事故出发,拆解向量数据库爆火的真实原因,深入底层索引机制和架构取舍,分析融合趋势。给从业者一个清醒的判断框架。
|
1月前
|
存储 固态存储 关系型数据库
DBA凌晨查账单:每月5万的云数据库竟有一半在空转,我的六个优化动作和数据验证
从一次真实的云数据库成本优化复盘出发,分享实例规格合理选型、冷热数据分层、存储压缩、弹性伸缩策略、清理历史数据、预留实例规划六个关键步骤,附优化前后的成本对比数据和操作要点。
|
1月前
|
存储 固态存储 关系型数据库
从月账单5万到3.5万:云数据库成本优化的完整复盘
上云本应是降本增效,但很多企业上云之后,账单反而越滚越大。实例规格买高了、历史数据堆在SSD上、测试环境没人关、过期快照没清理——每一笔费用都在悄悄累积。本文从云账单的三大“黑洞”出发,拆解云成本失控的根因,给出实例降配、冷热数据分层、僵尸资源清理三条可落地的优化路径,帮助DBA和运维工程师用数据驱动成本优化,让每一分钱都花在刀刃上。
|
1月前
|
SQL 运维 监控
慢查询日志的“高级用法”:从找慢SQL到做容量规划
慢查询日志是DBA最熟悉的工具,但大多数人只用它来找“跑得慢的SQL”。如果只做到这一步,你只用了慢查询日志20%的价值——剩下的80%是建立性能基线、预测容量瓶颈、评估优化效果、发现潜在风险。本文从慢查询日志的进阶用法出发,讲解如何通过持续记录慢查询建立性能基线、如何通过慢查询趋势预测容量瓶颈、如何将慢查询日志从“故障排查工具”升级为“容量规划工具”,帮助读者从“出了问题再查”升级到“看着趋势主动调整”。
|
1月前
|
存储 关系型数据库 MySQL
查询从45秒降到0.3秒,存储从1.2TB缩到180GB:IoT时序数据选型复盘
5万台IoT设备日增4.3亿行数据,MySQL三天崩溃的完整复盘。从写入模型、B+树瓶颈、Gorilla压缩原理对比时序库与关系型数据库的根本差异,含宽窄表重构SQL、冷热分离迁移策略、time_bucket查询优化,以及3条实战避坑经验。
|
1月前
|
缓存 NoSQL 关系型数据库
CXL内存池化趋势:数据库架构师需要提前关注什么
CXL 3.0开始送样,4.0规范已发布,内存池化正在成为现实。从缓冲池、缓存层到存算分离,聊聊这项技术会让哪些数据库架构受益,哪些被动挨打。
|
1月前
|
SQL JSON 算法
SQL执行计划的“成本模型”:读懂cost,理解优化器为什么选这个计划
EXPLAIN能告诉你优化器选了哪个执行计划,但说不出它为什么这么选——明明有索引它却走全表扫描,明明A计划更快它却选了B计划。优化器不靠猜,它靠一套成本模型(Cost Model)做决策。本文从优化器的成本模型出发,拆解cost的构成(IO_cost、CPU_cost、memory_cost),讲解如何通过EXPLAIN FORMAT=JSON和OPTIMIZER_TRACE看到优化器的“思考过程”,并通过真实案例展示优化器“算错账”的根因,帮助读者从“知道选了谁”升级到“理解为什么选它”。

热门文章

最新文章