都 2025 年了,还不试试 PostgreSQL?

AI 生成的摘要

加载中...

(此服务由 xLog 驱动)

都 2025 年了,还不试试 PostgreSQL?

一、前言:MySQL 已经成了惰性的象征,而非技术的选择

MySQL 曾经是互联网时代的功臣,它简单、便宜、够快。但到了 2025 年,它更多代表的是行业的惯性与保守。人们继续用它,不是因为它先进,而是因为它“还活着”。然而,如果你把目光放到数据库设计层面,就会发现:MySQL 根本不是一个完整的关系数据库,而是一个带 SQL 外壳的存储系统。

它的事务,只覆盖了一部分数据; 它的 ACID,是有注脚的; 它的优化器,是随缘的; 它的触发器,是残废的; 它的约束,是可关闭的。

MySQL 靠“够用”生存; PostgreSQL 靠“正确”延续。

两者之间的区别,不是实现多少特性, 而是——是否尊重数据库科学本身。


二、优化器:MySQL 靠猜,PostgreSQL 靠算

MySQL 的查询优化器还停留在上个世纪。它基于规则,不基于代价。

SQL
CREATE TABLE orders (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  user_id INT,
  status VARCHAR(20),
  created_at DATETIME,
  INDEX idx_user_status (user_id, status)
);

EXPLAIN SELECT * FROM orders WHERE user_id = 42 AND status = 'done';
EXPLAIN SELECT * FROM orders WHERE status = 'done' AND user_id = 42;
Copy

逻辑上完全相同的两条 SQL:

  • 第一条走索引;
  • 第二条却全表扫描。

因为 MySQL 优化器死板地按索引定义顺序匹配列,不会重排谓词,也不计算组合代价。稍不注意写法,性能直接爆炸。

而 PostgreSQL 的优化器是真正的代价模型(Cost-Based Optimizer)。它通过列统计与数据分布做决策,执行计划稳定、可预测。

PostgreSQL 的计划是理性计算; MySQL 的计划是随机猜测。

当你的系统需要确定性性能,MySQL 这个优化器就成了炸弹。


三、ACID 的幻觉:回滚之后,MySQL “干净地”抹掉历史

MySQL 的最大谎言,是那句印在官网上的口号:

“InnoDB fully supports ACID transactions.”

这句话听上去像承诺,实际上是选择性履行。遇见 DDL,MySQL 立刻撕毁契约。

看看这一段再平常不过的表迁移事务:

SQL
START TRANSACTION;

-- 1. 改名原表
RENAME TABLE metrics TO metrics_1;

-- 2. 按旧结构创建新表
CREATE TABLE metrics LIKE metrics_1;

-- 3. 导入旧数据
INSERT INTO metrics SELECT * FROM metrics_1;

-- 4. 删除旧表
DROP TABLE metrics_1;

-- 5. 写入日志(假设这里出错)
INSERT INTO system_events(event_type, description)
VALUES ('table_upgrade', 'metrics table upgraded');

ROLLBACK;
Copy

你以为 ROLLBACK 是“回到从前”? 在 MySQL 里,它意味着“请擦干净尸体再走”。

执行之后你会得到:

  • 原表 metrics 被改名再删除;
  • 新表 metrics 还在,但空无一物;
  • 数据彻底消失;
  • 那条日志既没写入,也没留下痕迹。

你手动发起了回滚,MySQL 则帮你干净地抹掉了历史。

更荒谬的是,这不是 bug,而是官方设计。 任何 DDL(RENAME、CREATE、DROP)都会触发隐式提交。事务还没结束,它就自作主张地写死文件。

结果是:回滚只是摆设,原子性形同虚设。你的事务,不是安全网,而是引爆器。出错时,它炸的不是异常,而是数据本身。


PostgreSQL 的对比:真正的事务,是一次数据库级时间穿越

在 PostgreSQL 中,同样的操作是完全事务化的:

SQL
BEGIN;

ALTER TABLE metrics RENAME TO metrics_1;
CREATE TABLE metrics (LIKE metrics_1 INCLUDING ALL);
INSERT INTO metrics SELECT * FROM metrics_1;
DROP TABLE metrics_1;
INSERT INTO system_events(event_type, description)
VALUES ('table_upgrade', 'metrics table upgraded');

ROLLBACK;
Copy

一旦执行 ROLLBACK:

  • 所有表、结构、数据、索引全部回退;
  • WAL 写前日志完整重放;
  • 系统状态恢复如初,连指针都不漏一页。

这不仅仅是“支持 DDL 事务”,这是数据库哲学分界线的实证:

PostgreSQL 的事务作用于整个数据库状态; MySQL 的事务只作用于部分数据文件。

前者是有意识的系统,它理解什么叫“一致性”、“原子性”、“时间线”;后者只是一个文件操作堆栈——连“状态”都不懂。

毫不夸张地说:

PostgreSQL 的事务是一个原子行为; MySQL 的事务是一个概率事件。

前者以逻辑守护数据; 后者赌机器别出错。

PostgreSQL 管整个宇宙;MySQL 只管几张文件。 这是工程实现的鸿沟,更是理念上的耻辱。


四、触发器与逻辑:MySQL 的断肢,PostgreSQL 的神经系统

MySQL 到今天的触发体系依旧严重残缺:

  • 每个事件只能定义一个触发器;
  • 不支持语句级触发;
  • 不支持条件触发;
  • 调试如地狱,复用无可能。

2025 年,你依然能看到这样的报错信息:

ERROR 1235 (HY000): This version of MySQL doesn't yet support multiple triggers for the same table.
Copy

而 PostgreSQL 的触发体系,是成熟的事务内逻辑层:

  • 行级与语句级触发并存;
  • 支持条件判断(WHEN);
  • 可指定顺序、共存多个;
  • 可用多语言编写(PL/pgSQL、Python、C)。

在 PostgreSQL,触发器能形成业务层逻辑护城河; 在 MySQL,它只是挂件。


五、约束与一致性:MySQL 允许造假,PostgreSQL 不允许撒谎

MySQL 允许你在一行命令里掐死完整性保障:

SQL
SET FOREIGN_KEY_CHECKS = 0;
Copy

然后导入任意垃圾数据。再恢复检查,它也不会重验。 完美的“装死”机制。

PostgreSQL 没有这种妥协选项。 约束永远生效、永远执行。 它不会假装一致 —— 它要么成功,要么拒绝。

MySQL 教你撒谎;PostgreSQL 逼你诚实。

更离谱的是,MySQL 在处理外键与复合索引时的行为,完全超出直觉。

假设你有一个主表与子表结构如下:

SQL
CREATE TABLE users (
  id INT PRIMARY KEY,
  name VARCHAR(50)
);

CREATE TABLE orders (
  id INT PRIMARY KEY,
  user_id INT,
  name VARCHAR(50),
  INDEX idx_user (user_id, name),
  FOREIGN KEY (user_id) REFERENCES users(id)
);
Copy

理论上,这里的外键只约束 user_id,与 name 无关。但在 MySQL 中,只因为你建立了联合索引 (user_id, name),它会在某些版本(尤其 5.x 与早期 8.0)中无端把第二列 name 一并纳入外键校验逻辑。任何 name 冲突、甚至非唯一匹配,都会触发外键报错。这意味着你根本没定义外键到 name,却被 MySQL 的外键机制“顺手管了”。

PostgreSQL 不会做这种事。 它认得标准:外键依赖主键或唯一约束列,不会跨字段、不会超范围、不会瞎猜。

MySQL 的问题在于:它将“联合索引”视作“外键实现细节”,把数据约束混在索引选型里,最终让行为变得既不确定又难以调试。

PostgreSQL 则严格区分:索引是优化器的工具,外键是一致性的契约。MySQL 把契约和工具绑死在一起。

当你加个索引时,你同时改变了逻辑规则——这不是数据库,这是雷区。


六、“数据库只是大号 Excel”?

不,那只是被 MySQL 教坏的一代人

有人说:

“逻辑不要放数据库,数据库只是存储。”

这句话听上去理性,其实是悲哀。

悲哀的是:MySQL 把开发者养成了“不信任数据库”的人。

因为:

  • 事务不完整;
  • 约束能关;
  • 触发器假死;
  • 优化器靠缘分。

于是程序员被迫把一致性逻辑搬到应用层,再对自己说:“逻辑不应在数据库中做。”

结果就是 ORM、幂等、防重复、补偿机制满天飞。只是因为 MySQL 从未完成应尽职责。

而 SQL 标准在 1992 年就已完整确立:

  • 标准事务语义(包含 DDL);
  • 外键与约束机制;
  • 触发器与存储过程;
  • 视图、模式、授权体系。

换句话说,在 MySQL 出生之前,SQL 世界已经有了成熟、完整、被各大数据库验证过的科学定义。

但到了 1995 年,MySQL 出场时,它做了一个惊人的选择: 它没有遵守科学,不继承标准,而是自创一套残废版 SQL,命名为——“My SQL”。注意那个 “My”:它不是对个人的归属表达,而是一个注脚

“我只承认属于我自己的 SQL 规则。”

于是它扭曲了语言逻辑、删掉了事务 DDL、阉割了触发器、弱化了外键,再把这些残缺包装成“轻量”“高性能”“互联网友好”。 事实上,那不过是权衡实现复杂度后的技术懒惰与规范背叛。

这就是 MySQL 的原罪:当全世界都在遵守《SQL-92》, 它却在实现 “Only My SQL”。

结果,MySQL 教坏了一代开发者:大家开始认为数据库就是 CRUD 容器;开始把一致性逻辑扔回应用代码;一边疲于修补,一边自诩解耦优雅。

MySQL 不止是技术问题,它是一种文化病毒 ——它让人们习惯无标准、无事务、无尊严的数据库生态, 并且还为此自豪。

当他们说“数据库只是 Excel”,真正的意思是:

“我们用的 MySQL 就像 Excel——能存点数据,却没灵魂。”


七、有人说“事务里做 DDL 不科学”?

不,那只是被 MySQL 吓坏的工程师自我安慰

会有人批评文中这一点,说:

“在事务里执行 DDL 是不科学的设计。”

这句话听起来高冷,实际上是 MySQL 弱点导致的错觉。他们不是在阐述数据库原理,而是在为 MySQL 找借口。

事实是:事务中执行 DDL 并不反常,这本应是关系数据库的标准语义。 但因为 MySQL 拉跨,他们被迫认为‘不能做’,然后自我合理化。

他们记住的是 MySQL 的崩溃方式, 于是开始以为数据库就该如此; 于是把“不敢”包装成“原则”; 把数据库降级成“存储层”; 再用代码去弥补数据库应有的功能。

PostgreSQL 没这个问题。 你可以在事务里安全地改表、建表、删表、回滚。 因为它的 DDL 就是事务的一部分, 它不装模作样,不偷偷提交。

所以请停止把 MySQL 当作数据库的定义。 它只是数据库的简化版、阉割版、历史遗迹。

真正科学的,是 PostgreSQL; 真正错误的,是被 MySQL 教坏的世界。

要正确性,就别怕高级。 要数据库,就别怕事务中的 DDL。

MySQL 的恐惧,不该成为你的惯性。 真正的数据库,不需要妥协。

MySQL 教人屈服;PostgreSQL 教人尊重。

八、分库分表:互联网最成功的错误设计

所谓“分库分表”,在今天被吹嘘成互联网架构的成功案例。但事实恰恰相反——它不是进化结果,而是 MySQL 贫瘠设计的自我赎罪。

MySQL 从来没有真正的分区机制、全局索引、全局统计信息,也没有跨表事务优化器。当数据量增大,它无法逻辑扩展,只能物理切割。 于是“分库分表”登场——不是因为聪明,而是因为没办法。

从此,应用层开始接管数据库的职责。程序员被迫在业务代码中:

  • 自行计算分片位置;
  • 写路由中间件决定 SQL 去哪;
  • 实现伪分布式事务补偿;
  • 拼接跨库聚合查询;
  • 再写一层定时脚本同步数据。

这一切,只是为了修补一个不支持现代分区能力的数据库。而这些补丁行为,居然被包装成“高并发经验”,仿佛“用应用弥补数据库的残缺”就成了架构智慧。这就像一辆没有刹车的汽车,司机们开始总结撞墙减速的技巧, 然后把它写进《高速驾驶指南》。

分库分表从来不是架构突破,而是数据库退化的症状。

PostgreSQL 从未需要靠这种土法生存。它的分区、并行与事务一致性都在数据库层自然发生。它遵循 SQL 标准,并实现了真正意义上的逻辑分区表——在保持事务一致的同时,可无限水平扩展。

例如,一个标准的时间分区表:

SQL
-- 创建主表并定义分区键
CREATE TABLE logs (
    id BIGSERIAL PRIMARY KEY,
    user_id BIGINT NOT NULL,
    action TEXT,
    created_at TIMESTAMP NOT NULL
) PARTITION BY RANGE (created_at);

-- 创建分区表
CREATE TABLE logs_2024 PARTITION OF logs
    FOR VALUES FROM ('2024-01-01') TO ('2025-01-01');

CREATE TABLE logs_2025 PARTITION OF logs
    FOR VALUES FROM ('2025-01-01') TO ('2026-01-01');

-- 插入数据时自动路由到正确分区
INSERT INTO logs (user_id, action, created_at)
VALUES (1, 'login', now());

-- 查询仍然是针对一个逻辑整体
SELECT user_id, COUNT(*) FROM logs
WHERE created_at >= '2025-01-01'
GROUP BY user_id;

-- 扩展新分区只需一句
CREATE TABLE logs_2026 PARTITION OF logs
    FOR VALUES FROM ('2026-01-01') TO ('2027-01-01');
Copy

数据量再大,它依然是一个逻辑整体。分区是扩展,不是切割;事务仍完整,优化依然智能;一致性从未退让。

因为 PostgreSQL 的设计宗旨是:

当系统变大,正确性不该变小。

而 MySQL 的哲学是另一种:

“先跑起来,崩溃再想办法。”

于是,一个数据库不承担数据库的职责,行业就开始弥补它的缺陷——写代理、造中间件、讲分片策略、造轮子、开大会、出白皮书。所有人都在修补 MySQL 的伤口,而非构建数据库的未来。

如果说 PostgreSQL 推动了数据库技术的演化,那么 MySQL 推动的,只是分库分表的产业链。它让无数人困在自造的迷宫里,同时以此误以为“这就是大规模架构的真相”。

真相是:成熟的数据库不需要你去分它。分库分表不是荣誉勋章,而是系统设计的病历单。它见证的不是成功,而是退化——见证了一个数据库如何拒绝成长,又如何让整个行业去替它长大。

PostgreSQL 让系统扩展正确性; MySQL 让系统扩展复杂性。

分库分表不是智慧,是悲剧的形式美。

九、结语:要正确性,不要幻觉

MySQL 的哲学是:差不多就行。

PostgreSQL 的哲学是:必须正确,否则失败。

对比项MySQL 5.7PostgreSQL 12
事务原子性仅 DML,DDL 会隐式提交全局原子性
优化器规则匹配,性能漂移成本模型,推理稳定
外键与约束可关闭或跳过严格强制执行
触发器功能残缺事务级完整
DDL 事务不支持,必隐式提交完全支持,可回滚
SQL 标准方言化实现完全兼容 ANSI SQL
扩展方式分库分表(应用层路由)原生分区表(数据库层)
事务一致性跨库 XA,慢如狗全局 ACID
查询语法动态拼接统一 SQL
扩容成本停机 + 迁移ATTACH PARTITION
是否优雅像修下水道像写 SQL

到了 2025 年,
如果你还在忍受一个:

  • ROLLBACK 会删光你表的数据库;
  • 允许你关闭外键检查的数据库;
  • 靠猜测计划运行的数据库;
  • 需要你写中间件来“分库分表”的数据库

那你不是在用数据库, 你是在赌数据库别出事故。

MySQL 属于过去 —— 它是“差不多”的象征; PostgreSQL 属于未来 —— 它是“正确性”的代名词。

停止为 MySQL 的残缺买单。
真正的架构师,不造轮子补洞,而是选择一个不用补的数据库。

要么 PostgreSQL,要么幻觉。
要么正确,要么坍塌。

此文章已经由它的创作者签名并安全地存储在区块链上。