$kernelink route --hydrate --safe

页面加载 /
跳到正文
20.md
workspace / posts
~/posts/20.md 阅读中

线上慢SQL排查思路:四步黄金流程+根治方案

TECH DIARY

线上慢SQL排查思路全攻略

2026年7月28日 · 先止损再定位后根治防复发 · IT中华技术日记

IT中华 本文整理线上慢 SQL 排查的黄金四步流程:先止损 → 再定位 → 后根治 → 防复发,附 SpringBoot+Druid 监控代码与常见根因对照表。

第一步:紧急止损

  1. 确认影响范围:APM 工具(SkyWalking/Pinpoint)定位慢接口
  2. 快速熔断降级:核心接口被打挂时降级非核心功能
  3. Kill 异常慢查询show full processlist; 找到耗时 >10s 线程,kill [id];
  4. 流量切分:读压力切从库,写压力暂关非核心写

第二步:精准定位

数据库层面(80%问题在这里)

-- 当前运行线程
show full processlist;

-- 慢查询日志(阈值建议1s)
show variables like 'slow_query_log';
show variables like 'long_query_time';

-- 分析执行计划(最关键)
explain select * from user where name = '张三';
-- 关注 type / key / rows / Extra

应用层面(剩余20%)

  • N+1 查询:循环调用数据库查关联表
  • 大分页limit 1000000, 10 扫描前百万行
  • 长事务/大事务:占用连接,导致其他请求排队

第三步:针对性根治

常见原因解决方案
全表扫描创建联合索引,遵循最左前缀
索引失效避免函数/运算/隐式转换/like '%x'
大分页游标分页:where id > last_id limit 10
N+1查询批量查询 where id in (...)
大事务拆分事务,移出非DB操作

第四步:防复发

  • 上线前 SQL 审核:Druid、SonarQube 自动检测
  • 压测验证:全链路压测模拟真实流量
  • 监控告警:慢查询超 1s 自动报警
  • 定期巡检:每月清理无用索引,优化表结构

技术亮点代码

大分页优化(性能提升1000倍)

// ❌ 扫描前100万行
selectPage(offset, pageSize);

// ✅ 游标分页(基于自增ID)
@Select("select id,name,phone from user " +
        "where id > #{lastId} order by id asc limit #{pageSize}")
List<User> selectByCursor(@Param("lastId") long lastId, @Param("pageSize") int pageSize);

N+1 查询根治

// ❌ N次查用户
for (Order o : orders) {
    User u = userMapper.selectById(o.getUserId());
}

// ✅ 批量查询(1次)
Set<Long> ids = orders.stream().map(Order::getUserId).collect(toSet());
Map<Long,User> map = userMapper.selectByIds(ids).stream()
    .collect(toMap(User::getId, identity()));

IT中华 小结:监控先发现 → 工具抓SQL → EXPLAIN看计划 → 结合场景挖根因 → 建索引/改写法/调架构 → 验证闭环。永远先观测再动手,线上最怕凭直觉改代码。隐式类型转换(varchar字段传int值)导致索引失效,是最高频的坑。

关于IT中华

IT中华(www.itzh.vip)持续关注后端开发与数据库性能。本文转载改写自博客园 Rain 的 Java 大神实战圈技术文章。关注IT中华,获取更多实战排查经验。

IT中华 · www.itzh.vip · 技术日记

comments.cmd 可写入
guest@kernelink:~/posts/20$ comment --compose
identity.env 访客信息
插入 访客会话 Text + UBB · UTF-8 · LF 0 字符