时尚

SQL修复

时间:2010-12-5 17:23:32  作者:休闲   来源:娱乐  查看:  评论:0
内容摘要:凌晨两点十七分,我盯着屏幕上那行血红的报错——ERROR 1062: Duplicate entry '10086' for key 'PRIMARY'——咖啡杯沿的指纹已经干成了白圈。这已经是本周第

凌晨两点十七分,我盯着屏幕上那行血红的报错——ERROR 1062: Duplicate entry '10086' for key 'PRIMARY'——咖啡杯沿的指纹已经干成了白圈。这已经是本周第三次因为同一张表的自增主键撞车而回滚事务了。

问题出在三个月前的一次迁移。当时DBA老周拍着胸脯说“用INSERT INTO ... SELECT导数据没问题”,结果源库的AUTO_INCREMENT计数器没跟着搬过来。新库的表里已经有了id=10086的记录,但计数器还停在10085。每次业务侧手动插入不带id的行,MySQL就傻乎乎地从10086开始发号,然后撞个满怀。

修复SQL本身不难。先查当前最大id:SELECT MAX(id) FROM orders;,再重置自增起点:ALTER TABLE orders AUTO_INCREMENT = 10087;。真正难的是说服业务方接受这个方案——他们担心改表结构会锁表,影响凌晨的批量结算任务。我翻了半天慢查询日志,确认这条ALTER语句在InnoDB下其实只修改元数据,不重建表,才敢在凌晨三点半执行。整个过程花了不到两秒,但等待监控指标恢复平稳的那五分钟,比写十条复杂SQL都煎熬。

不过今天想聊的不是这种教科书式的修复。上周遇到个更隐蔽的坑:某个统计报表的SQL从上周二开始偶发超时,但看执行计划又一切正常。排查到第三天,才发现是另一个团队在优化他们的归档任务时,往user_login_log表上加了把LOCK_READ的MDL锁——他们的长事务没提交,导致我们的SELECT被堵在锁等待队列里。你说气不气?两边都觉得自己没改错,但合在一起就出了鬼。

这种跨团队的SQL问题最磨人。你没法靠单条语句修复,得去协调别人的发布窗口,甚至要推动建立锁监控的告警机制。最后我们妥协的方案是给报表查询加了个/*+ MAX_EXECUTION_TIME(2000) */的提示,让它在超时前主动放弃,而不是干等锁释放。治标不治本,但至少把故障从“接口整体不可用”降级成了“偶尔报个错重试一下”。

说回那些真正能靠SQL本身解决的修复。记得有一次,生产环境上有个UPDATE语句跑了四十分钟还没结束。我抓出它的执行计划,发现优化器选错了索引——它用了idx_created_at这个二级索引去回表过滤status字段,却不知道status列的选择性其实更高。修复办法很简单:在WHERE条件里加上FORCE INDEX(idx_status),或者干脆重建统计信息。但问题是,为什么统计信息会错得这么离谱?后来查出来,是前一天有人手动跑了个ANALYZE TABLE,但采样率设置得太低,把数据分布给带偏了。

SQL修复这活儿,百分之六十的精力花在搞清楚“为什么当初会写成这样”。剩下的百分之四十,是在各种约束之间找平衡——业务不能停,数据不能丢,性能不能崩。有时候你明明知道最优解是改表结构,但为了兼容某个老掉牙的客户端,只能写个更绕的查询绕过去。

最讽刺的是,很多所谓“修复”其实是给之前的烂摊子擦屁股。上周刚帮一个客户处理完他们的分页查询慢问题——他们用LIMIT 100000, 20去翻第五千页的数据,这种写法神仙来了也优化不动。改写成基于游标的分页后,响应时间从三秒降到了三十毫秒。客户连声道谢,我却忍不住想:当初写这个查询的人,到底是怎么想的?

算了,不猜了。数据库不会说谎,错的永远是人写的逻辑。修复SQL的过程,本质上是在和时间赛跑——跟业务增长的速度赛跑,跟同事留下的技术债赛跑,也跟自己的耐心赛跑。每当深夜改完一条语句,看着监控面板上的曲线重新归于平直,那种感觉比喝十杯浓缩咖啡都提神。

最近更新
热门排行
copyright © 2026 powered by 力不从心网   sitemap