MySQL 是蠢是坏,还是又蠢又坏
MySQL 最大的问题不只是几个 bug,而是它把一部分数据库能力做坏之后,又把这种坏经验训练成了行业常识。
你只是改了一下订单状态,结果买家表被锁住了。
订单状态在订单表里。买家信息在买家表里。按正常直觉,这两个动作不该互相打扰。外键要保护的是买家 ID 这种关联字段,不是订单状态这种业务字段。
但 MySQL 里事情偏偏就这么发生了:因为订单状态和买家 ID 出现在同一个 composite index 里,更新订单状态时,父表也被卷进了锁行为。
这不是“开发者不会用数据库”的问题。
真正别扭的地方在于:你很难从数据库基本原理里推导出这种结果。它不是那种“虽然复杂,但想通后合理”的设计,而更像一个长期使用者不得不记住的禁忌:这个功能别这么用,不然会出怪事。
于是,MySQL 的争议就不该只停在“它有没有 bug”。
更值得问的是:当一个工具足够普及,又把一些本来该可靠的能力做得反直觉,它会不会反过来改变一代程序员对数据库的想象?
烂工具最可怕的地方,不是它难用,而是它会重写行业常识。
“懂行的人都不用”这句话,本身就很可疑
很多 MySQL 使用者都听过一套经验:
Foreign Key 少用,Trigger 别用,Enum 少碰,Composite Index 别乱搞。
如果这句话只是提醒大家别滥用复杂功能,那没问题。工程里确实有很多功能不是“能用就该用”。外键会影响写入路径,触发器会增加隐式逻辑,枚举会带来迁移成本,复合索引也可能让优化器选择变复杂。
但问题是,这套经验在很多团队里已经变味了。
它不再是“理解代价后谨慎使用”,而是“懂行的人都不用”。
这就很奇怪。
Foreign Key 本来是关系数据库维持 referential integrity 的基础能力。Trigger 本来是数据库表达约束和副作用的一种方式。事务本来是数据库区别于电子表格的核心能力之一。你当然可以因为项目规模、团队习惯、迁移策略而不用它们,但如果一个生态里大量老手都把这些能力当雷区,那就说明问题不只是“用户没学好”。
有时所谓最佳实践,只是长期踩坑后的创伤反应。
这也是 MySQL 最有杀伤力的地方。它不只是让你踩坑,它还会让踩坑的人长出一套非常自洽的解释:数据库本来就不该管太多,业务逻辑都应该放应用层,表只要能 CRUD 就够了。
听起来很务实。
但这套务实背后,可能藏着一种被训练出来的贫瘠。

第一个坑:索引和外键不该这么纠缠
我们把视频里的例子简化一下。
一个订单表有买家 ID,也有订单状态:
| |
如果你更新的是 buyer_id,数据库需要检查父表、维护关系完整性,这很正常。
真正反直觉的是另一种情况:假设业务为了查询方便,建了一个包含 status 和 buyer_id 的复合索引。一个真实的案例里,只更新 status 这种非外键字段,也会牵动父表锁。
这类问题之所以恶心,不在于“加一个索引会不会影响执行计划”。所有数据库都会有执行计划,索引当然会改变访问路径。
恶心的是:一个看似服务查询性能的索引,突然改变了外键相关的锁行为。
你很难要求普通业务开发者每天在脑子里模拟这种副作用。更现实的结果是,团队内部会沉淀出一句粗暴的规矩:别用外键,别乱搞复合索引。
这句规矩短,容易传播,也能减少事故。
但它同时也把数据库的能力砍掉了一截。
第二个坑:事务不是你以为的那种事务
另一个更好理解的例子,是 DDL 和事务。
很多人对事务的直觉是:
| |
如果最后一步写审计失败,整个事务回滚。旧表还在,新表没有被写入,审计也没有留下半条记录。
这才是很多人脑子里“事务”的样子。
但在 MySQL 里,DROP TABLE 这类 DDL 语句会触发隐式提交。你不能把它当成普通事务里一个可以随时回滚的步骤。MySQL 8 之后有 Atomic DDL,但这说的是 DDL 语句自身要么完成、要么不完成,不等于它能被你包进普通 transaction 里跟 DML 一起回滚。
这两个概念差一点,事故就差很多。
如果迁移脚本里混着 INSERT、DROP TABLE、审计写入,最后审计失败,你以为系统会帮你回到原点,实际上旧表可能已经没了,新表又因为 DML 回滚而空了,审计记录也没有。
到这一步,你再跟老板解释“这是 MySQL 的隐式提交机制”,听起来就像在给删库找借口。
所以这里真正该学到的不是“所有 DDL 都别碰”。
而是:在 MySQL 里,DDL 和 DML 的事务边界不能靠直觉处理。迁移脚本要拆阶段,要先备份,要把不可逆动作放到明确的发布步骤里,要让审计记录和风险回滚策略先于 DROP 出现。
这不是洁癖。
这是知道某个工具在哪些地方不替你兜底。
MySQL 把数据库教窄了
站在这个角度看,MySQL 的问题就比“两个技术坑”大得多。
一个数据库如果只是某个功能不好用,用户会绕开它。绕开久了,团队会写规范。规范传给新人,新人就会以为这不是某个数据库的限制,而是数据库设计本来就该这样。
最后,经验变成常识,常识变成教育。
很多人刚入行时接触的第一个数据库就是 MySQL。教程这么写,面试这么问,公司规范也这么教:表结构简单一点,逻辑放应用层,外键别建,触发器别碰,数据库主要负责存取数据。
久而久之,数据库就被理解成“电子表格 + CRUD”。
这不是说业务逻辑都应该塞进数据库。那是另一个极端。
真正的问题是,如果你从一开始就被教育“数据库最好什么都别做”,你就很难想象另一种工程组织方式:让数据库承担一部分约束,让事务边界真的可靠,让数据完整性不全靠应用层自觉,让 schema 不只是表格字段,而是系统契约的一部分。
MySQL 最麻烦的地方,不是它有坑,而是它让很多人相信数据库本来就不该有能力。
这句话听起来刺耳,但很多团队的技术规范就是这么长出来的。
他们不是不懂数据库。
他们只是太懂 MySQL 了。
CRUD 没错,错的是只剩 CRUD
这里还要把话说清楚:CRUD 本身没错。
大多数业务系统,绝大多数时间确实都在做增删改查。订单要创建,库存要扣减,用户资料要更新,后台列表要查询。你不能因为数据库有更强的能力,就把所有业务逻辑都塞进触发器、存储过程和复杂约束里。
那会变成另一种灾难。
真正的问题不是 CRUD 太低级,而是团队把 CRUD 当成数据库的全部。只要数据库里出现一点“会主动约束数据”的东西,就觉得它越界了;只要 schema 里出现一点业务规则,就担心以后迁移麻烦;只要事务不只是包几条 UPDATE,就觉得不如应用层自己处理。
这种心态很常见。
它看起来是在保护系统,其实是在把系统最关键的一部分契约,交给“大家都记得”。
比如外键不用了,订单和用户的关系靠应用代码维护。一个服务写得很小心,另一个临时脚本未必小心。一个接口按顺序写,另一个批处理可能绕过去。最后数据坏了,大家再写一个巡检脚本,定时扫孤儿记录。
你看,约束没有消失。
它只是从数据库里的显性规则,变成了应用层、运维脚本、代码评审和事故复盘里的隐性规则。
这就是“只剩 CRUD”的真实代价:不是少用了几个高级功能,而是把本来可以由系统保证的东西,改成由人持续记住。
判断一个经验是不是被 MySQL 训练出来的
所以,遇到“我们团队不这样用数据库”的经验时,我会建议先别急着反驳,也别急着照抄。
先判断它是哪一种经验。
第一种,是通用工程经验。比如不要滥用触发器,不要让数据库里藏太多别人看不见的副作用,不要用复杂约束掩盖糟糕的数据建模。这些经验离开 MySQL 也成立。
第二种,是工具适配经验。比如某个版本的 MySQL 对某类 DDL、索引、锁行为处理得不够符合直觉,所以团队选择绕开。这也可以接受,但它应该被标注为“针对 MySQL 的取舍”。
第三种,才是最危险的:把工具适配经验包装成数据库真理。
一旦走到这一步,团队就很难再评估其他数据库。因为它不是在比较 PostgreSQL、SQLite、SQL Server、Oracle 或 MySQL 的能力边界,而是在拿 MySQL 训练出来的恐惧,审判整门数据库技术。
这就是认知污染最隐蔽的地方。
它不会告诉你“我污染了你”。
它只会让你觉得,自己特别懂行。
不是不用 MySQL,而是别被 MySQL 定义数据库
写到这里,很容易滑向一句廉价结论:MySQL 不行,换 PostgreSQL。
这句话太省事,也太没用。
MySQL 当然能用。它有巨大的生态,足够多的运维经验,足够成熟的工具链,足够低的组织学习成本。很多场景里,选择 MySQL 不是错误,而是最现实的工程决策。
但现实决策不等于认知投降。
你可以因为团队熟悉、业务简单、生态成熟而用 MySQL。你也可以决定不在 MySQL 里使用外键、触发器或复杂约束。但你最好清楚:这是针对某个工具、某个团队、某个风险模型做出的取舍,不是关系数据库天然就只能这么用。
这中间差别很大。
前者叫工程判断。
后者叫被工具驯化。
下次团队里再有人说“懂行的人都不用外键”,我建议不要急着争。先问四个问题:
- 我们不用它,是因为这个功能在当前数据库里代价太高,还是因为我们从来没认真评估过?
- 这个约束如果不放数据库,应用层靠什么保证?靠代码、流程,还是靠大家记得?
- 一旦多个服务同时写同一批数据,谁负责维护一致性?
- 我们是在选择 MySQL,还是在把 MySQL 的限制当成数据库的边界?
这四个问题比“支持 MySQL 还是反对 MySQL”更重要。
因为技术选型从来不只是选一个软件。
你同时也在选择团队未来会相信什么。
如果一个工具告诉你:别相信外键,别相信触发器,别相信数据库约束,别相信事务能覆盖结构变更。你当然可以继续用它,但至少要知道,那不是数据库世界的全部。
你以为自己学会了数据库,其实可能只是学会了绕开 MySQL。
而真正成熟的工程团队,不该让一个工具的缺陷,替自己定义整门技术的边界。