加入收藏 | 设为首页 | 会员中心 | 我要投稿 草根网 (https://www.0515zz.com/)- 数据工坊、大数据、建站、存储容灾、数据快递!
当前位置: 首页 > 教程 > 正文

站长必避的3个MySQL设计陷阱:半年一崩

发布时间:2026-11-07 14:30:48 所属栏目:教程 来源:DaWei
导读:  “这表主键加索引,不就完事了?”老张拍板那会儿,投影仪对焦不准,字全虚在墙上,像没睡醒的人写的草书。我原以为他真懂,结果他掏出手机查“MySQL怎么加索引”,边查边念 aloud:“ALTER TABLE…嗯…这个online=true是默认的

  “这表主键加索引,不就完事了?”老张拍板那会儿,投影仪对焦不准,字全虚在墙上,像没睡醒的人写的草书。我原以为他真懂,结果他掏出手机查“MySQL怎么加索引”,边查边念 aloud:“ALTER TABLE…嗯…这个online=true是默认的吧?”没人接话。空调在滴水,嗒、嗒、嗒,节奏比我们评审进度还稳。


  去年端午前两天上线的那个站内信模块——就那个带“已读未读”小圆点的,埋点都打了,漏斗也配了,结果灰度放了七天,转化率零点零二。不是没用户看,是压根查不出来谁看了。为什么?因为 read_status 字段没索引,但更致命的是,它跟 user_id 组合查询时根本没建联合索引,而 PRD 第三页写得清清楚楚:“支持按用户+时间范围批量标记已读”。王薇当场在白板上画了个 JOIN,粉笔断了两截,她捡起半截继续划,手抖。没人提醒她——那张表当时连 CREATE_TIME 都是 varchar(20) 存的“2024-05-31 10:23:47”,不是 datetime。我后来看日志,MySQL 每次都隐式转类型,执行计划里全是 type=ALL。半年后崩第一回,运维半夜电话说连接数满,查出来是凌晨三点有三百个并发在跑 SELECT FROM message WHERE user_id = ? AND read_status = 0 ORDER BY create_time DESC LIMIT 50 ——那个 create_time 在 varchar 上根本用不了索引。


  桌上那摞打印的需求单没人收,最上面那张边角卷起来了,印着“消息中心V2.3”标题。你翻过没?第一页写着“需兼容历史百万级消息数据”,可第二页性能要求那一栏空着,就画了个问号。后来排期排到“先做,后优化”,然后就没有然后了。李工说“反正MySQL扛得住”,结果扛到端午前一天,凌晨四点,他蹲服务器机柜前面,耳机线垂在地上,一边听磁盘响一边敲 SHOW PROCESSLIST,敲到第三遍时发现两个慢查询在互锁:一个在 UPDATE message SET read_status = 1 WHERE …,另一个在 INSERT INTO message_read_log … ——而 log 表的 user_id 字段居然没索引。他删掉 INSERT 语句里的子查询重写,重启服务,五点二十系统恢复。我没敢说,那个子查询里嵌了个 SELECT MAX(id) FROM message WHERE user_id = ?,而 message 表的主键 id 是自增的,但 user_id 上连个普通索引都没有。


文章配图,仅供参考

  我原以为加个索引就行,结果线上加完发现写入慢了30%。查了才知道,那表上有七个字段都建了单列索引,其中三个是布尔值(is_deleted、is_pinned、is_top),MySQL 为每个 INSERT 都要维护七棵 B+ 树。你猜怎么着?上线三个月后,DELETE 和 UPDATE 的 QPS 还不到 INSERT 的一半。老板在复盘会上说“功能交付了,数据没问题就行”,说完端起杯子喝了一口,杯底压着张外卖单,汤洒了一点在桌上,油花慢慢晕开,像张没加载完的 E-R 图。我没抬眼看他。王薇低头改 PRD,手机一直在震,震了六下,没接。老张中途出去接了个电话,回来直接说“这个需求优先级调低”,然后盯着我:“你说那个联合索引……到底是 (user_id, read_status, create_time) 还是 (user_id, create_time, read_status)?”我愣了两秒才反应过来他在问最左前缀——我说是前者,他点点头,拿红笔在PRD旁边打了个钩。红墨水洇开一点,像血。


  优胜劣汰嘛。不是人淘汰,是设计自己崩给你看。半年一崩,不是运气差,是每个决策点都选了“先上线再说”。去年端午崩那次,查到⭐️⭐️⭐️⭐️root cause 居然是 message 表里有个字段叫 ext_data,type 是 text,里面存了 JSON,而 PRD 写着“后续可能按 ext_data->'$.category' 做筛选”——但没人建虚拟列,也没人加函数索引。上线时 MySQL 版本是 5.7,不支持函数索引。今年升到 8.0 了,也没人想起这事。我上周看监控,那个 ext_data 的 LIKE 查询还挂在慢日志榜首,平均响应 2.8 秒。但没人提。李工说“又没影响主线流程”,老张说“等大促后再重构”,王薇改完 PRD 最后一页,把“技术债清单”那一栏删了,说“显得消极”。


  其实最吓人的不是崩,是崩完没人改。你见过哪个站长修完一个坑,顺手把旁边三个类似坑一起填了?没有。都是崩一次,补一刀,刀口还是斜的。我上周帮他们导出崩溃前五分钟的 slow log,总共 378 条,涉及五张表,其中三张的 create_time 字段类型不一致:两个 datetime,一个 timestamp,一个 varchar。我截图发群里,没人回。倒是有个人回了个“????”,然后撤回了。


  那把椅子少一把。会议室就十九把,今天来了二十个人。李工坐我左边,王薇坐我右边,老张坐我对面,中间空着那把,椅背上搭着件皱巴巴的衬衫,袖口磨得发亮。谁的?记不清了。大概是上周团建发的,蓝色,印着公司 logo。我盯着那logo看了三秒,突然想起来,logo底下那行小字是“让连接更简单”,可我们连一条 SQL 都连不明白。


  我下周五要陪运维搭个临时只读从库,分担查表压力。不是解决问题,是给问题争取点喘息时间。你要是真想避那仨陷阱——主键乱设、索引乱加、字段乱选——不如现在打开你库里最老的那张业务表,SHOW CREATE TABLE,然后盯住它,别动。盯够十分钟。如果手指没悬在 DROP INDEX 上,你就还没入门。

(编辑:草根网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!