MySQL运维设计5大陷阱:9年加载优化师亲历避坑指南
|
上个月跟总编吵完出来,工位上那杯美式已经结了一层油膜,我伸手去碰——凉的,但没喝,就搁那儿了。隔壁桌小陈手肘一歪,咖啡泼在键盘上,滴滴答答往下淌,他连擦都没擦,光顾着刷手机里刚弹出的DBA群消息:“主从延迟破百秒了”。我原以为是监控告警阈值设低了,结果查了三台中继日志,发现是凌晨两点自动补数脚本把从库IO线程堵死了,而那个脚本,是我三个月前签字放行的。 陷阱一:主键当索引用,还用BIGINT。不是不能用,是它根本不会“优胜劣汰”。我们线上一张用户行为表,六千八百万行,主键id bigint auto_increment,然后所有查询都靠where user_id = ? and created_at between ? and ? ——你猜怎么着?全表扫。因为user_id没索引。不是忘了加,是当初设计时说“先跑通逻辑,索引后加”,结果上线半年没人动DDL,开发觉得“查得还行”,运维觉得“QPS没爆”,测试觉得“用例过了”。直到某天促销页首屏加载从1.2秒跳到8.7秒,前端甩来一份Lighthouse报告,我才点开慢查日志——第一条就是这个user_id没走索引的join。我敢打包票:那个建表语句里,create_time字段默认值写的是CURRENT_TIMESTAMP,但没加ON UPDATE CURRENT_TIMESTAMP;这个细节我盯了四遍,不会错。 选题会上我推这稿子,总编翻白眼翻得颈椎咔一声响,笔一直没动,就斜插在笔筒里,笔帽早掉了。小编低头狂敲,指甲盖泛白,但屏幕上全是钉钉未读红点。我话说一半,财务部老张的手机响了,铃声是《最炫民族风》高潮段,震得我耳膜发麻,他接起来就说“哎哟李总您可算打来了……”然后端着保温杯出门了。我没拉回来,也不打算拉。反正这篇可能活不过三小时。
文章配图,仅供参考 陷阱二:JSON字段存结构化数据。上次做用户标签系统,开发说“灵活”,我点头说“可以”,心想顶多加个generated column配虚拟索引。结果他们直接把device_info、utm_source、ab_version全塞进一个json字段里,再配上一条update set tags = JSON_SET(tags, '$.v', '1.8.3') ——每条更新都重写整列,MVCC版本链暴涨,undo log三天爆一次。我们试过抽出来建单独表,但他们回邮件说“迭代太快,schema变更要走四道审批”,我回了一句“那你们把binlog格式切ROW吧”,对方读了已阅,没回。这个我说不准——到底是因为人手不够,还是因为压根不认账? 还有一次改配置,想调innodb_buffer_pool_size,线上有48G内存,我写了50%,结果执行前一核对,发现机器上跑了三个MySQL实例,都是同一批Ansible模板起的,buffer_pool全设成50%。我删掉重写,改成28G,但脚本注释里还留着旧的“# 建议:总内存×0.5”。那行注释我现在都记得,因为当时我在电梯里扫码——先按开门键,再掏手机,再等微信跳出小程序,再点“确认重启”。其实重启命令早输好了,在终端里闪着光。可我就盯着那个绿箭头,按了三次才点进去。扫码本身没毛病,但那个等待时间,长得像在等一个不回消息的人。 陷阱三:从库只做HA,不做读负载。上周我把所有报表查询全切到从库,一小时内触发三轮自愈:先是复制中断,因为主库一条update涉及三百二十万行的update,从库apply不过来;接着从库CPU干到99%,最后OOM killer亲手kill掉了mysqld进程。恢复后我查了下,那个报表SQL用了force index,强制走了一个已部分失效的复合索引——索引字段顺序和实际查询条件顺序反了。没人修,因为“业务方说这个报表一周只跑两次”。我们真这么信了。后来我自己写了个python脚本,每天凌晨三点扫一遍show slave status里的Seconds_Behind_Master,超过300秒就发钉钉+邮件+电话外呼(只给值班DBA)。现在外呼接口停了,换成语音转文字短信,因为值班的人说“半夜接电话比看告警还累”。 小王昨天提了个需求,想加个全文检索字段,我说“别,上Elasticsearch”,他说“太重”,我说“那就用MATCH AGAINST,别自己parse分词”,他点头走了。五分钟后钉钉弹窗:“张工,能帮忙看下这个SELECT MATCH(title) AGAINST(‘mysql优化’ IN NATURAL LANGUAGE MODE) 怎么总返回空?”我扫了一眼,没回,直接点了“已读”。这不是问题,是信号灯坏掉后的第一辆闯红灯的车——后面全跟着过。 陷阱四:字符集统一喊了八年,生产库还是UTF8MB3混UTF8MB4。不是不知道后果,是每次推进都卡在“兼容性验证”。比如有个旧系统用JDBC连接串没设useUnicode=true&characterEncoding=utf8,连上去insert中文就变成问号;开发说“改连字串怕其他模块崩”,我们说“那至少把新表建为utf8mb4”,结果他们用Navicat建表时顺手勾了“与模板一致”,模板还是latin1。上个月清理元数据,我导出information_schema.columns,grep charset,扫到第十八分钟时,发现system_log表的content字段明明定义为TEXT utf8mb4_unicode_ci,但建表语句里写着DEFAULT CHARSET=latin1 ——这俩根本矛盾,但MySQL真让它过了。我截图发群里,没人回,三分钟后,运营总监转发进来,标题叫《关于提升客户满意度的紧急动作》,底下没提字符集一个字。 陷阱五:慢查日志开着,但没人看。我们设了long_query_time=1,log_output=TABLE,写进mysql.slow_log。查了下,这张表有三百七十二万行。最大的那条,耗时19.82秒,扫描了五百六十万行,来源是某个定时任务的cleanup脚本,里面写着DELETE FROM event_history WHERE create_time < DATE_SUB(NOW(), INTERVAL 90 DAY),而create_time上没索引。我原以为是开发疏忽,结果查Git记录,这条SQL三年前就有,当时的commit message写的是“修复清理性能”,作者署名是当年的架构师,现已是CTO。我愣了一下,把窗口最小化,点开订餐App——外卖还在“派送中”,但时间显示“预计送达:17:03”,现在是17:05。 工资条还没发,绩效面谈排到下月十七号。我桌上那支笔,到现在还是斜插着,笔帽没找着。总编今天早上开会说“要抓技术水位”,我举手说“MySQL索引失效有七种典型路径,要不要列个checklist”,他点点头,转头就让小编统计“近三十天技术类选题点击率TOP5”。我喝了口冷美式,咽下去时嗓子有点痒。下次选题会,我打算闭嘴。或者带支新笔去。 (编辑:站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |


创业技术合规避坑指南:政策、数据与安全红线
SQL Server数据库设计避坑12实战要点
MySQL运维实战:36小时从崩溃到稳如磐石
Windows数据科学环境搭建:5年运维避坑实战
深度学习服务器选型避坑与全栈调优实战
鸿蒙开发者必修:MySQL运维设计实战
DBA熬夜改表?这本MySQL实战手册搞定设计与运维