线上SQL事故是多环节松动的集中爆发,复盘重在厘清“为何未拦截”:慢查询监控需执行时间与扫描行数双维度告警并动态调阈值;索引失效主因隐式转换、函数包裹或联合索引顺序错误;高危操作须代理层拦截、审批流程与权限最小化;EXPLAIN与实际性能脱节源于统计信息陈旧、数据倾斜或磁盘临时表。

线上SQL事故往往不是单点故障,而是多个环节松动后的一次集中爆发。复盘的核心不是追责,而是把“当时为什么没拦住”这个问题拆解清楚。
慢查询没被及时发现
很多数据库监控只看QPS、连接数、CPU,却漏掉执行时间超过1秒的SQL在缓慢爬升。这类查询初期不影响可用性,但会悄悄拖垮连接池、挤占缓冲区,最终引发雪崩。
- 建立按执行时间+扫描行数双维度的慢日志告警,阈值不能只设“>1s”,要结合业务节奏动态调整(比如大促期间放宽到2s,但增加全表扫描拦截)
- 定期用pt-query-digest分析慢日志,重点看“Rows_examined/Rows_sent”比值异常高的SQL——说明做了大量无效扫描
- 开发提测阶段就要求提供核心接口的SQL执行计划,DBA介入审核type是否为ALL或index,key_len是否合理
索引失效导致线上降级
明明加了索引,查询却走全表扫描。常见诱因不是没建索引,而是索引被隐式转换、函数包裹或联合索引顺序错位。
- WHERE col + 0 = 123、WHERE DATE(create_time) = '2024-01-01'这类写法会让索引完全失效
- 联合索引(a,b,c),如果查询条件只含b或c,无法命中;含a和c但跳过b,只能用上a
- 上线前用EXPLAIN FORMAT=TRADITIONAL验证每条关键SQL,重点关注possible_keys和key是否一致
误操作缺乏熔断机制
DELETE/UPDATE不带WHERE、ALTER TABLE在线锁表、DROP TABLE手抖回车——这些操作一旦发生,靠人工响应永远慢于故障扩散速度。
- 在数据库代理层(如ProxySQL、ShardingSphere)或中间件配置SQL拦截规则,例如禁止DELETE without WHERE、限制ALTER TABLE ... ADD COLUMN在业务高峰时段执行
- 高危操作必须走审批流程,通过运维平台提交,自动生成备份快照+回滚语句,并强制设置超时(如ALTER超时10分钟自动KILL)
- 日常账号权限最小化:应用账号禁用DROP、ALTER、CREATE;DBA账号启用二次确认+操作留痕
从执行计划到真实性能脱节
EXPLAIN显示走了索引,但实际执行仍很慢。原因常在于统计信息陈旧、数据倾斜严重、或临时表/排序溢出磁盘。
- 定期检查information_schema.TABLES中TABLE_ROWS与实际COUNT(*)偏差是否超30%,偏差大则手动ANALYZE TABLE
- 对ORDER BY + LIMIT组合,警惕Using filesort——若排序字段无索引,即使LIMIT 10,也可能先排100万行再取前10
- 监控Created_tmp_disk_tables指标突增,说明GROUP BY或子查询触发了磁盘临时表,需优化逻辑或调大tmp_table_size










