搜 索

关系数据库的选择:MySQL 对比 PostgreSQL

  • 3阅读
  • 2026年01月31日
  • 0评论
首页 / 编程 / 正文

前言

如果你在2010年问一个开发者选什么数据库,答案几乎是条件反射式的:"MySQL啊,还用问?"

但如果你在2025年问同样的问题,答案变得有趣了起来。越来越多的新项目在启动时选择了PostgreSQL,而MySQL似乎成了"历史遗留系统"的代名词。

这不是偶然。让我们从技术演进的角度,聊聊这场"数据库王座"的更替。

历史轨迹:两条不同的路

timeline title 数据库发展关键节点 1995 : MySQL 诞生 : 定位:快速、简单、够用 1996 : PostgreSQL 诞生 : 定位:学术严谨、功能完备 2000-2008 : LAMP 时代 : MySQL 成为 Web 开发标配 : PostgreSQL 被视为"过于复杂" 2008 : Sun 收购 MySQL 2010 : Oracle 收购 Sun : MySQL 发展方向开始不确定 2012 : PostgreSQL 9.2 : JSON 支持、性能大幅提升 2017 : PostgreSQL 10 : 逻辑复制、声明式分区 2020 : PostgreSQL 成为 DB-Engines 年度数据库 2022-2025 : PostgreSQL 连续霸榜 : MySQL 增长停滞

两个数据库诞生时间相近,但走了完全不同的路:

  • MySQL:选择了"够用就好",在 Web 1.0/2.0 时代凭借简单易用快速占领市场
  • PostgreSQL:选择了"做正确的事",早期被批评"过度设计",但这些设计后来都成了护城河

技术对比:细节里的魔鬼

事务与一致性

flowchart LR subgraph MySQL["MySQL (InnoDB)"] M1[REPEATABLE READ 默认] --> M2[间隙锁 Gap Lock] M2 --> M3[容易锁升级] M3 --> M4[并发问题多] end subgraph PostgreSQL["PostgreSQL"] P1[READ COMMITTED 默认] --> P2[真正的 MVCC] P2 --> P3[SSI 串行化] P3 --> P4[行为可预测] end style M4 fill:#ffcccc style P4 fill:#ccffcc

这是最核心的差异。支付、金融这类对一致性要求极高的场景,PostgreSQL 的事务模型显著更可靠:

特性MySQL (InnoDB)PostgreSQL
默认隔离级别REPEATABLE READREAD COMMITTED
SERIALIZABLE 实现基于锁,性能差SSI(串行化快照隔离),性能好
MVCC 实现Undo Log,长事务导致膨胀行内版本链,更优雅
间隙锁有,容易造成意外锁等待无,锁行为可预测
DDL 事务❌ 不支持✅ 支持

实际案例:MySQL 的间隙锁在高并发写入时经常造成"明明只想锁一行,结果锁了一片"的问题。这在支付扣款场景下是灾难。

深入 MVCC:同名不同命

MVCC(多版本并发控制)是现代数据库的灵魂。两者都号称支持 MVCC,但实现方式截然不同——这直接决定了高负载下的表现。

MySQL (InnoDB) 的 Undo Log 回溯模型:

sequenceDiagram participant TX_A as 事务A (读) participant Heap as 数据页 participant Undo as Undo Log 链 TX_A->>Heap: 读取行 (当前版本 V3) Heap-->>TX_A: 版本号 > 我的快照,不可见 TX_A->>Undo: 回溯查找 V2 Undo-->>TX_A: 版本号还是太新 TX_A->>Undo: 继续回溯 V1 Undo-->>TX_A: ✅ 可见!返回 V1 Note over Undo: 长事务 = 长链条 = 性能灾难

InnoDB 的数据页只保留最新版本的行数据,旧版本被推入 Undo Log 链表。读操作需要沿链表回溯,直到找到对当前事务可见的版本。短事务场景下没问题,但一旦出现长事务,噩梦就开始了:

flowchart LR LT[长事务不提交] --> UG[Undo Log 无法回收] UG --> CH[回溯链越来越长] CH --> SL[读操作变慢] SL --> MORE[更多事务堆积] MORE --> LT style LT fill:#ff9999 style MORE fill:#ff9999

真实踩坑场景:某支付系统中,一个忘记提交的统计查询事务存活了 2 小时,导致 Undo tablespace 膨胀到 50GB,整个库的写入性能下降 60%。DBA 半夜被叫起来 kill 掉事务后,purge 线程又花了 40 分钟清理 Undo Log。

PostgreSQL 的 Heap 内多版本模型:

sequenceDiagram participant TX_B as 事务B (读) participant Heap as 数据页 (Heap) participant VM as Visibility Map TX_B->>VM: 检查页面可见性 VM-->>TX_B: 该页面未全部可见 TX_B->>Heap: 扫描页内所有行版本 Note over Heap: V1 (xmin=100, xmax=200)
V2 (xmin=200, xmax=300)
V3 (xmin=300, xmax=∞) Heap-->>TX_B: 根据快照判断 V2 可见 TX_B->>TX_B: ✅ 返回 V2

PostgreSQL 的做法截然不同——新旧版本都存储在数据页(Heap)内,每行通过 xmin/xmax 标记创建和删除的事务 ID,通过 Visibility Map 快速跳过"全部可见"的页面。HOT(Heap Only Tuple)优化让不涉及索引列的更新直接在同一页内完成,避免索引维护。

代价是什么?旧版本不会自动消失,需要 VACUUM 来清理死元组。这是 PostgreSQL 运维的核心关注点。

两种模型的核心权衡:

graph TB subgraph InnoDB["MySQL InnoDB"] direction TB IA[✅ 数据页紧凑] --> IB[✅ 顺序扫描快] IB --> IC[❌ 长事务导致 Undo 膨胀] IC --> ID[❌ 读操作需要回溯链表] ID --> IE[❌ Purge 线程有延迟] end subgraph PG["PostgreSQL"] direction TB PA[✅ 读操作无需回溯] --> PB[✅ 无 Undo 膨胀问题] PB --> PC[❌ 数据页有膨胀
Table Bloat] PC --> PD[❌ 需要 VACUUM 维护] PD --> PE[✅ autovacuum 自动化] end style IE fill:#ffcccc style PE fill:#ccffcc
维度MySQL (InnoDB)PostgreSQL
旧版本存储位置Undo Tablespace(独立区域)Heap 数据页(就地存储)
读旧版本开销需回溯 Undo 链,链长则慢直接在页内扫描,开销稳定
膨胀风险Undo tablespace 膨胀表/索引膨胀(Table Bloat)
清理机制Purge 后台线程VACUUM(autovacuum 自动触发)
长事务影响灾难性:阻塞 Undo 回收可控:autovacuum 仍可工作
HOT 优化有,减少索引维护开销

一句话总结:MySQL 把复杂性藏在了 Undo Log 里,平时看不见,出问题时抓瞎;PostgreSQL 把复杂性摆在了台面上(VACUUM),逼你正视它,但行为更可预测。

数据类型与表达能力

mindmap root((数据类型)) PostgreSQL JSONB 二进制存储 数组类型 Array 范围类型 Range 几何类型 Geometry 网络类型 INET/CIDR 自定义复合类型 枚举 ENUM 可修改 UUID 原生支持 MySQL JSON 文本存储 ❌ 无数组 ❌ 无范围类型 需要扩展 VARCHAR 模拟 ❌ 无复合类型 ENUM 修改需 ALTER VARCHAR(36) 模拟

PostgreSQL 对复杂数据结构的原生支持,让很多场景下的表设计更自然:

-- PostgreSQL:存储用户标签,原生数组
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    tags TEXT[],  -- 原生数组类型
    metadata JSONB,  -- 二进制JSON,可索引
    ip_address INET,  -- 原生IP类型
    valid_period TSRANGE  -- 时间范围类型
);

-- 查询:找包含某标签的用户
SELECT * FROM users WHERE 'vip' = ANY(tags);

-- MySQL:只能用 JSON 或关联表模拟
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    tags JSON,  -- 文本存储,查询慢
    metadata JSON,
    ip_address VARCHAR(45),
    valid_from DATETIME,
    valid_to DATETIME
);

-- 查询:需要 JSON 函数,性能差
SELECT * FROM users WHERE JSON_CONTAINS(tags, '"vip"');

深入 JSONB:不只是"都支持 JSON"

虽然 MySQL 和 PostgreSQL 都支持 JSON,但底层实现完全不同——这个差异大到值得单独拎出来说。

flowchart LR subgraph MySQL_JSON["MySQL JSON"] MJ1["INSERT: 存储为文本"] --> MJ2["SELECT: 每次解析文本"] MJ2 --> MJ3["查询字段: JSON_EXTRACT
需遍历整个文档"] MJ3 --> MJ4["索引: 需创建虚拟生成列
再在生成列上建索引"] end subgraph PG_JSONB["PostgreSQL JSONB"] PJ1["INSERT: 解析为二进制格式"] --> PJ2["SELECT: 直接读取二进制"] PJ2 --> PJ3["查询字段: 二进制偏移
O(1) 直达目标"] PJ3 --> PJ4["索引: GIN 索引
一行搞定全部路径"] end style MJ4 fill:#ffe6e6 style PJ4 fill:#e6ffe6

MySQL 的 JSON 本质是"存进去时是文本,读出来时再解析";PostgreSQL 的 JSONB 是"存进去时就解析为二进制格式,读的时候直接按偏移量定位"。差距体现在索引上尤为明显:

-- PostgreSQL JSONB:一行创建 GIN 索引,所有字段都可高效查询
CREATE INDEX idx_metadata ON orders USING GIN (metadata);

-- 查询 metadata 中的任意字段,都走索引
SELECT * FROM orders WHERE metadata @> '{"payment_method": "apple_pay"}';
SELECT * FROM orders WHERE metadata ? 'discount_code';
SELECT * FROM orders WHERE metadata->>'region' = 'UAE';

-- MySQL:每个要查询的 JSON 字段都需要单独处理
ALTER TABLE orders ADD COLUMN payment_method VARCHAR(50) 
    GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(metadata, '$.payment_method')));
CREATE INDEX idx_payment_method ON orders(payment_method);
-- 每多查一个字段,就要重复一遍上面的步骤...

在包含 100 万行、每行 JSON 约 2KB 的表上,性能差距一目了然:

操作MySQL JSONPostgreSQL JSONB
单字段精确查询(有索引)~15ms(需生成列)~3ms(GIN 索引)
单字段精确查询(无索引)~800ms(全文档解析)~200ms(二进制直达)
多条件组合查询需多个生成列索引一个 GIN 索引覆盖
存在性检查(某 key 是否存在)JSON_CONTAINS_PATH,不走索引? 操作符,走 GIN

如果你的业务有"半结构化数据"需求(用户自定义属性、动态配置、多变的业务标签),JSONB 的优势是碾压级的。

索引能力

graph TB subgraph PostgreSQL["PostgreSQL 索引类型"] PB[B-tree] PH[Hash] PG[GiST 通用搜索树] PS[SP-GiST] PI[GIN 倒排索引] PR[BRIN 块范围索引] PP[部分索引] PE[表达式索引] PC[覆盖索引 INCLUDE] end subgraph MySQL["MySQL 索引类型"] MB[B-tree] MH[Hash 仅Memory引擎] MF[Full-text] MS[Spatial 需扩展] end style PostgreSQL fill:#e6ffe6 style MySQL fill:#ffe6e6

PostgreSQL 的索引能力碾压 MySQL:

索引特性PostgreSQLMySQL
部分索引WHERE status = 'active'
表达式索引ON (lower(email))❌ 需要生成列绕行
GIN 倒排✅ 全文搜索、JSONB、数组
BRIN✅ 时序数据神器
覆盖索引INCLUDE (col)✅ 但语法不同

实际收益:一个交易流水表,用 BRIN 索引按时间范围查询,索引大小是 B-tree 的 1/100,查询性能相当。

扩展性与生态

flowchart TB subgraph PG["PostgreSQL 扩展生态"] direction TB PostGIS[PostGIS 地理信息] TimescaleDB[TimescaleDB 时序数据] Citus[Citus 分布式] pgvector[pgvector 向量搜索] FDW[Foreign Data Wrapper] PLV8[PL/V8 JavaScript] PGAudit[pg_audit 审计] end subgraph MY["MySQL 扩展能力"] direction TB MG[GIS 基础支持] MX[X DevAPI] MR[MySQL Router] MN[NDB Cluster] end PG --> |"丰富的扩展生态"| PGOK[一个数据库解决多种问题] MY --> |"扩展有限"| MYNO[往往需要引入其他系统] style PGOK fill:#ccffcc style MYNO fill:#ffcccc

PostgreSQL 的扩展机制是它最强大的护城河:

  • PostGIS:地理信息系统的事实标准
  • TimescaleDB:时序数据库,完全兼容 SQL
  • pgvector:向量数据库,AI 时代的新宠
  • Citus:分布式扩展,微软出品
  • FDW:可以把任何数据源(MySQL、MongoDB、Redis、S3...)当成表来查

MySQL 在这方面几乎是空白,你想要额外功能,就得引入额外系统。

深入 PostGIS:不仅仅是"存个坐标"

MySQL 的 GIS 和 PostGIS 的差距,不是"谁强一点"的问题,而是"业余选手 vs 职业运动员"的差距。

graph LR subgraph MySQL_GIS["MySQL GIS"] MG1[ST_Distance 距离计算] MG2[ST_Contains 包含判断] MG3[ST_Buffer 缓冲区] MG4["基础几何运算
~30个函数"] end subgraph PostGIS["PostGIS"] PG1[1000+ 空间函数] PG2[拓扑 Topology] PG3[栅格 Raster] PG4[3D / 4D 对象] PG5[球面几何 Geography] PG6[路径规划 pgRouting] PG7[矢量切片 MVT] PG8[点云 Point Cloud] end MySQL_GIS -.->|"量级差距"| PostGIS style MySQL_GIS fill:#ffe6e6 style PostGIS fill:#e6ffe6

用一个外卖配送场景来感受差距——"找出距离骑手 3 公里内、且在配送区域多边形内的所有待配送订单,按距离排序":

PostgreSQL + PostGIS

-- 一条 SQL 搞定,精确到球面距离
SELECT 
    o.order_id,
    o.restaurant_name,
    ST_Distance(
        o.location::geography,  -- 自动走球面计算
        ST_SetSRID(ST_MakePoint(55.2708, 25.2048), 4326)::geography
    ) AS distance_meters
FROM orders o
JOIN delivery_zones dz ON ST_Contains(dz.polygon, o.location)
WHERE 
    o.status = 'pending'
    AND ST_DWithin(
        o.location::geography,
        ST_SetSRID(ST_MakePoint(55.2708, 25.2048), 4326)::geography,
        3000  -- 3公里,单位:米
    )
ORDER BY distance_meters
LIMIT 20;

-- 索引:GiST 空间索引,查询毫秒级
CREATE INDEX idx_orders_location ON orders USING GIST (location);

MySQL

-- MySQL 的困境
SELECT 
    o.order_id,
    o.restaurant_name,
    ST_Distance_Sphere(
        o.location,
        ST_GeomFromText('POINT(55.2708 25.2048)')
    ) AS distance_meters
FROM orders o
WHERE 
    o.status = 'pending'
    AND ST_Distance_Sphere(
        o.location,
        ST_GeomFromText('POINT(55.2708 25.2048)')
    ) < 3000
ORDER BY distance_meters
LIMIT 20;

-- 问题1:ST_Distance_Sphere 不走空间索引,全表扫描
-- 问题2:没有 ST_DWithin 的等价优化
-- 问题3:配送区域多边形判断精度有限
-- 问题4:需要 MBRContains + 二次过滤来绕行

PostGIS 的杀手级特性远不止距离计算:

flowchart TB PostGIS --> Topology["🔷 拓扑分析
道路网络、行政边界
确保几何对象共享边界"] PostGIS --> Raster["🗺️ 栅格处理
卫星图像、高程模型
地形分析"] PostGIS --> ThreeD["📐 3D 支持
建筑信息模型 BIM
城市三维可视化"] PostGIS --> pgRouting["🛣️ pgRouting
最短路径 Dijkstra/A*
旅行商问题 TSP"] PostGIS --> MVT["🧩 矢量切片 MVT
直接生成地图瓦片
替代 GeoServer"] style PostGIS fill:#4CAF50,color:#fff
💡 如果你的项目涉及外卖配送、网约车、地图导航、物流规划,PostgreSQL + PostGIS 几乎是唯一的开源生产级选择。MySQL 的 GIS 能力只够做"附近的人"这种入门功能。

深入 pgvector:AI 时代的终极加分项

2024-2025 年,RAG(检索增强生成)成为 AI 应用的标准架构。核心需求是:把文本/图片转成向量,然后快速找到最相似的内容。

flowchart LR Doc[文档/图片] --> Embed[Embedding 模型
OpenAI / Cohere] Embed --> Vec["向量 [0.12, -0.34, ...]
768~3072 维"] Vec --> Store[存储到哪?] Store --> Option1["专用向量数据库
Milvus / Pinecone / Weaviate"] Store --> Option2["PostgreSQL + pgvector"] Option1 --> Problem["❌ 额外运维
❌ 数据同步
❌ 事务不一致
❌ 增加架构复杂度"] Option2 --> Benefit["✅ 同一数据库
✅ 与业务数据 JOIN
✅ 事务保证
✅ 运维零增量"] style Problem fill:#ffcccc style Benefit fill:#ccffcc

pgvector 最大的杀手锏不是向量搜索本身——专用向量库在纯搜索速度上可能更快——而是它和业务数据在同一个库里

-- 安装扩展
CREATE EXTENSION vector;

-- 业务数据 + 向量,同一张表
CREATE TABLE knowledge_base (
    id SERIAL PRIMARY KEY,
    title TEXT,
    content TEXT,
    category VARCHAR(50),
    embedding vector(1536),  -- OpenAI ada-002 输出维度
    created_at TIMESTAMPTZ DEFAULT now()
);

-- HNSW 索引:近似最近邻
CREATE INDEX idx_kb_embedding ON knowledge_base 
    USING hnsw (embedding vector_cosine_ops)
    WITH (m = 16, ef_construction = 64);

-- 语义搜索 + 业务过滤,同一个查询!这是专用向量库做不到的
SELECT 
    title, content,
    1 - (embedding <=> $1::vector) AS similarity
FROM knowledge_base
WHERE category = 'payment_docs'  -- 业务字段过滤
ORDER BY embedding <=> $1::vector
LIMIT 5;
维度pgvectorMilvus / Pinecone
部署复杂度一条 CREATE EXTENSION独立集群,需要独立运维
与业务数据关联原生 JOIN、WHERE 过滤需要应用层二次查询
事务保证完整 ACID无或有限
亿级向量性能中等(适合千万级)强(专为此优化)
过滤+搜索混合原生支持,高效需要 pre-filter/post-filter

结论:除非你的向量规模在亿级以上且需要极致检索延迟,否则 pgvector 足以覆盖绝大多数 AI 应用场景。一个数据库解决所有问题,这才是真正的工程效率。

为什么 MySQL 掉队了?

fishbone-rl title MySQL 掉队的原因分析 治理问题 Oracle 收购后发展保守 社区分裂 MariaDB/Percona 开源许可证争议 技术债务 MyISAM 历史包袱 复制机制落后 优化器能力弱 架构限制 扩展机制不如 PG 数据类型贫乏 DDL 不支持事务 生态变化 云原生时代新需求 AI/向量搜索兴起 开发者偏好转移

1. Oracle 的"养子"困境

2010年 Oracle 收购 Sun 后获得 MySQL,但 Oracle 自己有商业数据库要卖。MySQL 的发展变得保守且缓慢,社区信任度下降。MariaDB、Percona 的分裂进一步分散了生态。

2. 技术债务累积

MySQL 早期为了"简单"做的很多妥协,在现代场景下成了负担:

graph LR A[早期设计决策] --> B[MyISAM 为默认引擎] B --> C[事务支持是后加的] C --> D[InnoDB 集成不够原生] D --> E[很多高级特性实现困难] style E fill:#ffcccc

3. 云原生时代的不适应

现代应用需要:

  • 逻辑复制:CDC、事件驱动架构 → PostgreSQL 原生支持,MySQL 需要 Canal/Debezium
  • JSON 文档:灵活 schema → PostgreSQL JSONB 完胜
  • 时序数据:IoT、监控 → TimescaleDB 无缝集成
  • 向量搜索:AI 应用 → pgvector 直接用

4. 开发者偏好转移

xychart-beta title "Stack Overflow 开发者调查:数据库使用趋势" x-axis [2018, 2019, 2020, 2021, 2022, 2023, 2024] y-axis "使用比例 %" 0 --> 60 line "PostgreSQL" [33, 35, 38, 41, 44, 49, 52] line "MySQL" [55, 54, 52, 50, 46, 42, 40]

年轻开发者更倾向于选择 PostgreSQL。这不仅是技术原因,也是文化原因——PostgreSQL 社区更开放、更活跃、更有创新精神。

公平地说:MySQL 的优势

批评要客观。MySQL 并非一无是处:

优势说明
简单读写性能简单 CRUD 场景,MySQL 略快
运维成熟度DBA 更多,资料更丰富
云服务成本Aurora MySQL 实例选择更多
存量系统大量成功案例(微信支付早期)
线程模型连接开销比 PG 的进程模型小

如果你的团队只熟悉 MySQL,且业务场景简单,继续用 MySQL 完全没问题。

深入连接模型:进程 vs 线程的真实影响

上面提到的"线程模型"优势值得展开聊——这是 MySQL 为数不多的、结构性优于 PostgreSQL 的地方。

flowchart TB subgraph PG_Model["PostgreSQL: 进程模型"] Client1[客户端1] --> Fork1[Backend 进程1
~10MB RSS] Client2[客户端2] --> Fork2[Backend 进程2
~10MB RSS] Client3[客户端3] --> Fork3[Backend 进程3
~10MB RSS] ClientN["客户端 5000+"] --> ForkN["进程 5000+
💥 内存爆炸"] end subgraph MY_Model["MySQL: 线程模型"] MC1[客户端1] --> Thread1[线程1
~256KB] MC2[客户端2] --> Thread2[线程2
~256KB] MC3[客户端3] --> Thread3[线程3
~256KB] MCN["客户端 5000+"] --> ThreadN["线程 5000+
✅ 内存可控"] end style ForkN fill:#ffcccc style ThreadN fill:#ccffcc

PostgreSQL 为每个连接 fork 一个独立进程,隔离性好但内存开销大。在超高并发连接场景(5000+),裸用 PostgreSQL 会吃掉大量内存。

解决方案:用 PgBouncer 做连接池,这是 PostgreSQL 生态的标配组件:

客户端 (5000连接) → PgBouncer (连接池) → PostgreSQL (50-100个实际连接)

实际上,即使 MySQL 也推荐使用连接池(ProxySQL),所以这个差距在生产环境中被大幅缩小了。但如果你的架构是 Serverless(大量 Lambda 函数直连数据库),MySQL 的线程模型确实更友好。

选型决策树

flowchart TD START[新项目数据库选型] --> Q1{需要复杂数据类型?
JSON/数组/地理/向量} Q1 -->|是| PG1[选 PostgreSQL] Q1 -->|否| Q2{高并发写入?
金融/支付场景} Q2 -->|是| Q3{团队熟悉度} Q2 -->|否| Q4{需要扩展能力?
时序/全文搜索/GIS} Q3 -->|都熟悉| PG2[选 PostgreSQL
事务模型更可靠] Q3 -->|只熟悉MySQL| Q5{能接受学习成本?} Q5 -->|能| PG3[选 PostgreSQL
长期收益大] Q5 -->|不能| MY1[选 MySQL
但要注意间隙锁问题] Q4 -->|是| PG4[选 PostgreSQL] Q4 -->|否| Q6{团队现状} Q6 -->|有MySQL经验| MY2[MySQL 可以] Q6 -->|都是新手| PG5[选 PostgreSQL
学一个更强的] style PG1 fill:#ccffcc style PG2 fill:#ccffcc style PG3 fill:#ccffcc style PG4 fill:#ccffcc style PG5 fill:#ccffcc style MY1 fill:#ffffcc style MY2 fill:#ffffcc

除了决策树覆盖的维度,还有两个容易被忽略的"隐藏变量":

  1. 连接模型:如果是 Serverless 架构(大量短连接),MySQL 原生更友好;用 PostgreSQL 需要配 PgBouncer
  2. JSON 使用强度:如果业务中有大量半结构化数据查询,PostgreSQL 的 JSONB + GIN 索引带来的性能优势是量级差距,不是调优能弥补的

版本推荐(2026年1月)

如果你决定选择 PostgreSQL:

风格推荐版本说明
稳妥派PostgreSQL 17.4+已验证1.5年,功能与稳定性的最佳平衡
激进派PostgreSQL 18.x增量备份增强,但验证时间较短

如果你决定继续使用 MySQL:

风格推荐版本说明
推荐MySQL 8.4 LTS长期支持版本
备选MySQL 9.xInnovation 版本,新特性多但非 LTS

结语

MySQL 并没有变差,是 PostgreSQL 变得太强了。

这就像诺基亚和 iPhone 的故事——诺基亚的手机依然能打电话,但智能手机重新定义了"手机"应该是什么样子。

PostgreSQL 用二十年时间证明了"做正确的事"的价值。那些当年被嘲笑的"过度设计",如今都成了最珍贵的特性。而 MySQL 早期为了"快速占领市场"做的妥协,变成了难以偿还的技术债务。

但也别忘了一个工程原则:最好的数据库不是功能最强的,而是你的团队能驾驭的。 PostgreSQL 的 VACUUM 调优、连接池配置、查询计划理解门槛都比 MySQL 高。如果团队没有足够的经验,贸然迁移可能带来的问题比技术收益更大。

正确的路径是:

flowchart LR A[新项目] --> B[默认选 PostgreSQL] C[存量 MySQL 项目] --> D{遇到瓶颈了吗?} D -->|没有| E[继续用,别折腾] D -->|有| F{瓶颈是 MySQL 造成的吗?} F -->|是| G[评估迁移成本
渐进式迁移] F -->|不是| H[先优化架构和代码] style B fill:#ccffcc style E fill:#ffffcc style H fill:#ffffcc

新项目选 PostgreSQL,老项目别轻易动。 这不是技术信仰,是工程理性。


本文写于 2026 年 1 月。数据库领域变化快,具体选型请结合最新情况判断。

评论区
暂无评论
avatar