学完这篇,你能在十分钟内判断下一个项目该用 PostgreSQL 还是 MySQL,并且知道迁移时最容易出问题的几个点在哪里。
一、先看三条结论
不绕弯子,先给结果:
- 纯 Web 内容站、读多写少、团队运维人手少 → MySQL
- 复杂查询、JSON 混存、地理数据、要做分析或向量检索 → PostgreSQL
- 拿不准 → 看你用的框架和面板生态。比如 Clara BBS 这类 PHP 论坛系统明确要求 MySQL 5.7+,那就别折腾;它内置的读写分离、Redis 缓存和百万级帖子支撑,在 MySQL 上已经跑得很稳。
二、功能对比:类型系统与索引能力
PostgreSQL 的优势集中在“数据库本身能做的事多”:
- 数据类型:原生数组、JSONB(二进制存储、可建 GIN 索引)、范围类型、枚举、复合类型、几何类型。MySQL 8.0 有 JSON,但没有数组和范围类型。
- 索引种类:B-tree、Hash、GIN、GiST、BRIN、SP-GiST,支持部分索引(
WHERE 条件索引)、表达式索引、INCLUDE 覆盖索引。
- 高级 SQL:窗口函数、CTE、
LATERAL、行级安全策略(RLS)、物化视图。
- 扩展生态:PostGIS、pg_trgm、pgvector、TimescaleDB,
CREATE EXTENSION 一行装好。
MySQL 的优势集中在“周边成熟”:
- 主从复制、半同步、组复制(Group Replication)、InnoDB Cluster 方案成熟,第三方中间件(ProxySQL、MyCat)选择多。
- LAMP 系面板(宝塔等)一键安装,运维门槛低。
- 云厂商 RDS 起步价通常更低。
验证一下你手上的实例支持什么:
-- MySQL 8.0
SELECT VERSION();
SHOW ENGINES;
SHOW VARIABLES LIKE 'innodb_version';
-- PostgreSQL
SELECT version();
SELECT * FROM pg_available_extensions WHERE installed_version IS NOT NULL;
注意:MySQL 的 utf8 是 3 字节的坑,建库建表一律用 utf8mb4,否则存 emoji 和部分生僻字会直接报错截断。
三、性能对比:先分清你的查询长什么样
“谁更快”是个伪问题,要拆成两类负载看:
短查询、高并发、主键读写——两者差距不大,MySQL 在简单点查和短事务上常略占优,InnoDB 原地更新、聚簇索引让主键顺序写入非常高效。
大表 JOIN、聚合、复杂分析——PostgreSQL 的优化器更强,支持 nested loop、hash join、merge join 多种连接算法和更丰富的统计信息。MySQL 8.0 才引入 hash join,此前复杂 JOIN 只能走 nested loop,容易出慢查询。
几个必须知道的性能差异点:
- 更新代价:PostgreSQL 更新是写新行版本,靠 autovacuum 回收,表膨胀需要监控;MySQL InnoDB 原地更新,但用随机 UUID 做主键会造成页分裂。
- 主键选择:两边都建议自增/有序主键,别拿 UUID 当聚簇主键。
- 调优入口:MySQL 看
SHOW ENGINE INNODB STATUS、EXPLAIN ANALYZE;PostgreSQL 看 pg_stat_statements、EXPLAIN (ANALYZE, BUFFERS)。
注意:PostgreSQL 上线后一定要调 autovacuum 参数(autovacuum_vacuum_scale_factor 等),高写入表不调,几周后查询会明显变慢且找不到原因。
四、场景对比:直接对号入座
| 场景 | 推荐 | 理由 |
|---|
| 论坛、博客、CMS、企业官网 | MySQL | 生态适配好,PHP 系程序基本只支持 MySQL |
| 电商订单、支付流水 | MySQL 或 PG | 两者事务都可靠,看团队熟悉度 |
| 报表、BI、数据仓库 | PostgreSQL | 窗口函数、并行查询、CTE 更强 |
| GIS / 位置服务 | PostgreSQL | PostGIS 基本没有对手 |
| AI 向量检索 | PostgreSQL | pgvector 直接内嵌,省一套组件 |
| 强约束的复杂业务模型 | PostgreSQL | CHECK、排除约束、RLS 表达力强 |
五、迁移时的方言清单
真要换库,这几处必改:
- 标识符引号:MySQL 用反引号 `
col ,PG 用双引号 "col"`,且 PG 会把未加引号的标识符折叠为小写。
- 自增:
AUTO_INCREMENT → GENERATED BY DEFAULT AS IDENTITY(或 SERIAL)。
- Upsert:
INSERT ... ON DUPLICATE KEY UPDATE → INSERT ... ON CONFLICT (...) DO UPDATE。
- 字符串聚合:
GROUP_CONCAT → string_agg。
- 空值处理:
IFNULL → COALESCE(PG 也认 COALESCE)。
- 日期格式化:
DATE_FORMAT(d,'%Y-%m-%d') → to_char(d,'YYYY-MM-DD')。
- 分页:都支持
LIMIT ? OFFSET ?,但深分页两边都要改成基于游标(keyset)翻页。
注意:MySQL 默认端口 3306,PostgreSQL 5432。生产环境别用默认端口裸奔,防火墙只放行应用服务器 IP。
小结
- 选型先看团队和生态,再看功能:能用框架原生支持的库,就别为了“技术先进性”换。
- PostgreSQL 强在类型系统、索引种类、复杂查询和扩展生态;MySQL 强在运维成熟、云服务便宜、PHP/Java 生态适配广。
- 性能对比必须绑定查询形态,短查询看 MySQL,复杂分析看 PostgreSQL。
- 换库的真正成本在 SQL 方言和运维习惯,不在数据导入本身。
- 无论选哪个,
utf8mb4、有序主键、autovacuum/慢查询监控这几件事都不能省。