MySQL慢SQL瓶颈定位

一、整体分析思路

遵循「耗时拆分 → 执行计划定位 → 资源/锁/IO排查 → 语句逻辑分析 」四步,先分清是扫描多、排序/分组、锁等待、IO高、网络/返回数据量大哪一类瓶颈。

二、第一步:拆分SQL总耗时(区分时间去向)

一条SQL总耗时 = 执行耗时 + 锁等待耗时 + IO耗时 + 网络传输耗时

先通过日志/状态判断时间花在哪。

1. 从慢查询日志提取核心指标

慢日志单条记录关键字段:

  • Query_time总执行时间(核心)
  • Lock_time:等待表/行锁的时间
  • Rows_sent:返回给客户端的行数
  • Rows_examined:MySQL实际扫描的行数
  • Rows_read:读取数据行数

快速判断瓶颈类型

  1. Lock_time 占比高 → 瓶颈:锁竞争(并发高、事务长、行锁升级为表锁)
  2. Rows_examined 远大于 Rows_sent → 瓶颈:无效扫描(索引失效/无索引)
  3. Query_time 高、行数不多、出现 filesort/temporary → 瓶颈:排序/临时表
  4. Rows_sent 极大 → 瓶颈:返回数据过多、网络传输慢
  5. 磁盘IO飙升、CPU高 → 瓶颈:全表扫描/大量随机IO

三、第二步:EXPLAIN 深度分析执行计划(核心瓶颈定位)

EXPLAIN 是定位SQL内部瓶颈的核心,按字段逐一判断问题点,按优先级从高到低排查。

1. 访问类型 type(最关键,代表数据读取方式)

优先级:system > const > eq_ref > ref > range > index > ALL

type 值 瓶颈说明 严重程度
ALL 全表扫描,逐行遍历整张表,CPU+IO双重消耗 严重,必须优化
index 全索引扫描,比全表扫描略好,但依然遍历整个索引树 高,需优化
range 范围查询(> < between in like 前缀匹配),范围过大则性能差 中等,看扫描范围
ref/eq_ref 正常索引命中,无明显瓶颈 正常

典型场景type=ALL 基本可以确定是缺失索引或索引失效

2. key / possible_keys(索引使用情况)

  • possible_keys:理论可用索引
  • key=NULL未使用任何索引,主瓶颈就是索引问题
  • key 有值但 type=ALL:索引存在但被SQL逻辑规避,索引失效

3. rows(预估扫描行数)

MySQL预估需要扫描的行数,数值越大,IO/CPU开销越高

  • 单表查询:几十万+行扫描 = 严重瓶颈
  • 多表JOIN:驱动表rows大,会导致后续表循环匹配次数暴增

4. Extra 额外信息(隐藏瓶颈重灾区)

这是排序、分组、临时表、回表等隐性瓶颈的主要来源:

  1. Using filesort

    • 含义:无法利用索引排序,MySQL在内存/磁盘做文件排序
    • 瓶颈:排序消耗CPU+临时IO,数据量越大越慢
    • 触发:ORDER BY 字段无索引、排序字段不在联合索引末尾、多字段排序顺序不一致
  2. Using temporary

    • 含义:MySQL创建临时表存放中间结果
    • 瓶颈:临时表涉及内存/磁盘读写,并发下性能暴跌
    • 触发:GROUP BYDISTINCTUNION、子查询、多表聚合无索引
  3. Using index

    • 含义:覆盖索引,无需回表查询数据,性能最优,无瓶颈
  4. Using where

    • 正常:索引过滤后再行条件判断;
    • 异常:配合 type=ALL 代表全表扫描后逐行过滤,开销极大。
  5. Using join buffer (Block Nested Loop)

    • 含义:JOIN 关联字段无索引,使用连接缓冲区做嵌套循环
    • 瓶颈:多表关联严重低效,属于JOIN索引缺失问题。

5. id & select_type(子查询/关联查询瓶颈)

针对多表、子查询、UNION语句:

  • DERIVED:派生表(子查询生成临时表),高频出现则是瓶颈
  • SUBQUERY:无法优化的子查询,执行多次,叠加耗时
  • 多表id混乱、执行顺序不合理:JOIN 驱动表选择错误(大表驱动小表)

四、第三步:区分四大类典型性能瓶颈+根因分析

结合日志 + Explain,把问题归为4大类,精准定位根因。

类别1:索引类瓶颈(最高发)

现象

  • Explain:type=ALL/indexkey=NULL
  • 慢日志:Rows_examined 极大,Lock_time 正常

根因

  1. Where/Order by/Group by 字段未建索引
  2. 索引失效:隐式类型转换、索引列运算/函数、like %xxxor 跨索引、is not null/not in
  3. 索引区分度太低(低基数索引,如性别、状态),MySQL放弃使用
  4. 联合索引顺序不合理(未遵循最左匹配)

类别2:排序/分组瓶颈(filesort + temporary)

现象

  • Explain:Using filesort / Using temporary
  • 慢日志:扫描行数不多,但 Query_time 偏高

根因

  1. ORDER BY / GROUP BY 字段未纳入联合索引
  2. 聚合、去重操作(DISTINCT、UNION)数据量过大
  3. 内存排序空间不足,排序落地到磁盘文件

类别3:锁/事务瓶颈(并发场景高发)

现象

  • 慢日志:Lock_time 占总耗时 30% 以上
  • 实时 show processlist:大量会话处于 Locked 状态

根因

  1. 事务执行时间过长,行锁迟迟不释放
  2. 批量更新/删除无索引,行锁升级为表锁
  3. 并发争抢同一行数据,锁等待队列堆积
  4. 死锁(会话互相等待)

类别4:数据量/IO/网络瓶颈

现象1:大结果集返回

  • 慢日志:Rows_sent 成千上万行
  • 现象:查询本身很快,但客户端接收数据慢
  • 根因:SELECT *、未分页、一次性返回全量数据,网络传输+客户端解析耗时高

现象2:大分页瓶颈

  • 语句:LIMIT 100000, 10
  • 根因:MySQL需要先扫描前10万行再丢弃,偏移量越大扫描行数越多

现象3:磁盘IO瓶颈

  • 服务器监控:磁盘读IO 100%、CPU 偏高
  • 根因:频繁全表扫描、无覆盖索引导致大量回表查询、临时表/排序落地磁盘

五、第四步:实时状态辅助分析(线上运行中SQL)

适合排查正在执行的慢SQL,补充静态日志的不足。

1. show full processlist

  • 状态 Copying to tmp table:正在创建临时表 → 临时表瓶颈
  • 状态 Sorting result:正在排序 → filesort 瓶颈
  • 状态 Locked:被锁阻塞 → 锁瓶颈
  • 状态 Sending data:正在传输结果集 → 网络/返回数据量大

2. 系统状态变量(全局负载)

sql 复制代码
-- 查看全表扫描次数
show global status like 'Handler_read%';
-- 临时表统计(磁盘临时表多=严重瓶颈)
show global status like 'Created_tmp%';
-- 文件排序次数
show global status like 'Sort%';
  • Created_tmp_disk_tables 持续上涨:大量临时表落地磁盘
  • Sort_merge_passes 高:排序内存不足,多次合并排序文件

六、快速分析流程(实战速用)

  1. 看慢日志:对比 Lock_time / Rows_examined / Rows_sent,初步划分瓶颈大类
  2. 执行 EXPLAIN:优先看 typekeyExtra,确认索引、排序、临时表问题
  3. 结合 processlist + 服务器监控:判断是否锁、IO、CPU 资源瓶颈
  4. 回看SQL语法:检查是否分页不当、SELECT *、索引失效写法、不合理子查询/JOIN

七、补充:常见误区

  1. 只看执行时间,不看扫描行数:有些SQL耗时1秒,但扫描百万行,并发后直接雪崩
  2. 有索引就万事大吉:索引失效、联合索引顺序错误依然会慢
  3. 忽略锁等待:并发场景下,锁等待比SQL本身执行更耗时
  4. 轻视临时表/文件排序:数据量上涨后,这两类问题会指数级变慢
相关推荐
czhc11400756633 小时前
6.11:halcon,Sqlserver;项目sql连接;git
git·sql·sqlserver
iiiiyu3 小时前
IO流相关编程题
java·大数据·开发语言·数据结构·数据库·mysql
AIOps打工人3 小时前
数据库运维工具选型 2026 横评:dbskiter vs MySQL Workbench vs percona_toolkit vs Navicat
运维·数据库·mysql
这个DBA有点耶3 小时前
核心系统的高可用与容灾架构:从主从到两地三中心全面解析
java·开发语言·数据库·sql·mysql·架构·运维开发
jieyucx4 小时前
数据库专题开篇:零基础迈入 MySQL 的第一步
数据库·mysql
minji...4 小时前
MySQL数据库 (六) MySQL表的约束(下),自增长约束,唯一键约束,外键约束,索引
数据库·mysql·索引·外键·唯一键·外键约束·自增长约束
未秃头的程序猿4 小时前
别再手写SQL了!我用Text2SQL让产品经理自己查数据,Java后端终于解脱了
后端·sql·ai编程
wangbing11254 小时前
MySQL的另类语法
数据库·mysql
超哥--4 小时前
B站视频内容智能分析系统(六):Text-to-SQL 结构化查询
数据库·sql·音视频