400-920-5594
173-6014-8050
首页 > 资讯中心 > 技术分享
MySQL慢查询治理实战:故障止损、根因定位、SQL调优、事前防控完整手册
2026-08-19 82 技术分享

成都软件开发

  线上系统经常出现一种诡异现象:系统刚上线性能尚可,随着业务数据量上涨,数据库CPU持续走高,部分接口响应越来越慢,严重时直接引发大量超时,甚至拖垮整个业务库⚠️。

  很多故障并不是服务器硬件不足,而是慢SQL日积月累带来的恶果。一条未优化的SQL,在十万、百万级数据下,足以把数据库资源耗尽。

  不少团队只懂得事后加索引临时救急,缺少完整的治理流程,同类故障反复复现。本篇文章完整覆盖故障应急、定位手段、调优技巧、代码改造、上线前置检查,提供可直接复制的SQL与Java代码,建立完整慢查询防护体系。

一、慢SQL带来的线上真实危害💥

成都软件开发

  • 数据库CPU持续打满,正常读写请求排队阻塞

  • 业务接口大面积超时,前端请求报错、页面加载缓慢

  • 锁等待、死锁风险上升,出现数据更新卡死

  • 主库压力过大,主从延迟持续扩大,读从库数据不一致

  • 严重场景直接数据库雪崩,整体业务不可用

重点提醒:慢查询危害会随数据量放大,小数据环境测试完全正常,上线跑一段时间后才集中爆发。本地单元测试很难发现这类隐患。

二、线上突发慢查询:第一步先应急止损✅

线上故障优先保障业务可用,不要上来就调SQL、改索引,先止损再排查根因。

1.查看数据库当前运行会话

-- 查看正在执行的SQL,Time字段代表执行耗时(秒)
SHOW FULL PROCESSLIST;

找到执行时间很长的慢SQLID,执行kill杀掉会话,临时释放数据库压力。

KILL 会话ID;

2.业务侧临时应急手段

  • 对慢查询对应接口增加限流,避免大量请求压垮数据库

  • 热点查询临时上Redis缓存,绕开数据库查询

  • 非核心功能临时降级,优先保障核心业务流程

三、如何精准捕获慢SQL🔍

方式1:开启MySQL慢查询日志

-- 查看慢查询配置
SHOW VARIABLES LIKE 'slow_query_log%';
SHOW VARIABLES LIKE 'long_query_time';

-- 动态开启慢查询日志,执行超过1秒即记录
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1;

生产环境建议长期开启慢查询日志,长期收集耗时异常SQL,做到问题早发现。

方式2:应用层Druid监控采集慢SQL(Java项目常用)

Druid连接池可以配置SQL监控,设置阈值自动记录耗时过高SQL,不需要依赖数据库日志。

spring:
  datasource:
    druid:
      filter:
        stat:
          slow-sql-millis: 1000
          log-slow-sql: true

方式3:链路追踪工具定位

SkyWalking、Pinpoint这类链路组件,可以直接看到每一条数据库SQL执行耗时,快速定位是哪个业务接口产生慢查询。

四、EXPLAIN执行计划分析,定位SQL瓶颈📊

成都软件开发

拿到慢SQL之后,不要盲目加索引,使用explain分析执行计划,判断索引是否生效。

EXPLAIN SELECT id,order_no,amount,status FROM orders WHERE user_id=10086 AND create_time > '2026‑01‑01';

重点关注几个核心字段:

  • type:访问类型,性能从优到劣 system > const > eq_ref > ref > range > index > ALL;尽量避免ALL全表扫描

  • key:实际最终使用的索引,如果为NULL代表索引失效

  • rows:预估扫描行数,数值越大性能越差

  • Extra:额外信息,出现Using filesort、Using temporary代表出现文件排序、临时表,性能较差

五、高频索引失效场景,很多项目踩坑💡

成都软件开发

  • 索引字段上做函数运算、类型转换,例如where date(create_time)=xxx

  • 隐式类型转换:字符串字段传入数字,索引失效

  • 复合索引不遵守最左匹配原则

  • like查询以%开头,无法命中索引

  • or条件一侧字段没有索引,导致整体索引失效

  • 数据分布差异过大,MySQL优化器放弃索引,选择全表扫描

六、典型慢SQL案例优化实战

案例1:大偏移量分页问题

错误写法,offset很大,数据库扫描大量无用数据:

SELECT * FROM orders WHERE status=1 ORDER BY id DESC LIMIT 100000,20;

优化方案,主键子查询过滤,减少扫描行数:

SELECT o.* FROM orders o INNER JOIN (SELECT id FROM orders WHERE status=1 ORDER BY id DESC LIMIT 100000,20) t ON o.id = t.id;

案例2:索引字段使用函数,索引失效

错误写法:

SELECT * FROM orders WHERE DATE(create_time)='2026‑08‑01';

改写为范围查询,保留索引生效:

SELECT * FROM orders WHERE create_time >='2026‑08‑01 00:00:00' AND create_time < '2026‑08‑02 00:00:00';

七、Java业务层规避慢查询的编码实践

很多慢查询根源来自业务代码编写习惯,下面给出生产中可直接参考的编码规范。

/**
 * 慢查询防护工具示例:禁止一次性大批量全量查询
 */
public class DbQueryUtil {

    /**
     * 分页安全查询,防止不加分页条件导致全表扫描
     */
    public static void checkPageParam(Integer pageSize){
        // 限制单次最大查询条数,避免一次性查出几十万行
        if(pageSize != null && pageSize > 2000){
            throw new RuntimeException("单次查询数量不能超过2000,请调整分页参数");
        }
    }
}

开发编码几条硬性规范:

  • 禁止不带任何条件直接查询全表数据,业务查询必须有限制条件、分页限制

  • select不要写*,只查询业务真正需要字段,减少回表开销、网络传输

  • 批量查询in集合不能过大,in里面数值建议控制在1000以内

  • 大表尽量避免join多张表,复杂逻辑放到业务代码处理

  • 不要在循环里面执行数据库查询,优先批量查询

八、优化之后,必须做验证📋

修改索引、改写SQL之后,不能直接上线,需要做验证:

  1. 使用explain确认执行计划,确认type、key符合预期,不再全表扫描

  2. 模拟线上数据量级,真实测试SQL执行耗时

  3. 评估新增索引带来的写入开销,索引不是越多越好,索引会降低insert/update性能

  4. 小流量灰度上线,观察数据库监控指标,CPU、慢查询数量是否下降

九、构建事前防控,避免慢查询上线🔥

治理慢查询最高效的方式,不是故障之后救火,而是开发阶段就拦截风险SQL上线。

  • 代码评审重点Review复杂SQL、大表查询逻辑

  • 测试环境导入模拟大数据量,复现慢查询,小数据测不出性能问题

  • 接入SQL审核工具,DDL、SQL变更上线前自动检测风险

  • 线上持续监控慢查询日志,定期巡检,提前发现潜在隐患

  • 定期梳理大表,单表数据量持续上涨,提前评估读写分离、分库分表方案

十、总结📌

成都软件开发

  慢查询治理不是简单加索引,而是一套完整闭环流程:故障应急止损 → 捕获慢SQL → explain分析定位根因 → SQL与索引优化 → 业务代码规避风险 → 上线验证 + 事前巡检防控

  很多团队只做优化,忽略事前防控,导致同类故障反复出现。数据量会持续增长,今天跑得很快的SQL,未来随着业务增长,就有可能变成慢SQL。建立常态化监控与检查机制,才可以长期保障数据库稳定运行。

  我们提供数据库性能诊断、慢SQL整体治理、索引优化、大表改造、读写分离方案落地、线上故障排查等软件技术服务,帮助业务系统解决数据库性能瓶颈。


推荐文章查看更多》