MySQL CPU飙高排查的全流程指南

 更新时间:2026年03月20日 08:41:12   作者:半桶水专家  
当 MySQL 出现 CPU 持续飙高 时,问题往往不只存在于数据库本身,而可能涉及:SQL 执行效率,系统资源瓶颈以及并发模型等,本文提供一套 工程化三阶段排查方法,需要的朋友可以参考下

当 MySQL 出现 CPU 持续飙高 时,问题往往不只存在于数据库本身,而可能涉及:

  • SQL 执行效率
  • 系统资源瓶颈
  • 并发模型
  • 内核调度
  • I/O 或网络行为

本文提供一套 工程化三阶段排查方法

主机层定位 → 系统层分析 → MySQL 内部根因

目标是精准回答三个问题:

  1. CPU 被谁消耗?
  2. 为什么消耗?
  3. 如何优化?

第一阶段:确认问题范围(定位 CPU 消耗主体)

目标:明确 是谁在消耗 CPU

  • MySQL 整体?
  • 单个线程?
  • SQL 计算?
  • 内核系统调用?

1.1 查看主机整体 CPU 负载

命令

top -c 

CPU 行解读

%Cpu(s): 10.4 us, 2.6 sy, 0.0 ni, 86.5 id, 0.1 wa, 0.0 hi, 0.4 si, 0.0 st 
字段含义判断
us用户态 CPU高 → SQL 计算密集
sy内核态 CPU高 → 系统调用频繁
waI/O 等待高 → 磁盘瓶颈
id空闲低 → CPU 真正繁忙

经验判断

  • us > 70% → SQL 问题概率极高
  • sy 高 → 锁 / 内核调度问题
  • wa 高 → I/O 伪 CPU 高

Load Average 判断

load average: 8.2, 7.9, 6.5 

规则:

Load > CPU 核心数 = 系统过载

示例:

  • 4 核 CPU
  • load = 8
    ➡ 存在运行队列堆积

1.2 定位 MySQL 进程 PID

ps -ef | grep mysqld
# 或
pidof mysqld

记录 PID,例如:

12345 

1.3 查看 MySQL 内部线程 CPU(关键步骤)

MySQL = 多线程模型
一个连接 ≈ 一个线程。

top -H -p 12345 -d 1 

场景分析

✅ 场景 A:单线程 100%

含义:

单条慢 SQL

行动:

  • 记录线程 ID
  • 去 MySQL 查 SQL

✅ 场景 B:大量线程均高

含义:

并发过高 / 连接风暴

行动:

  • 检查连接池
  • 限制最大连接

✅ 场景 C:线程不高但整体 CPU 高

可能原因:

  • MySQL 后台线程
  • 锁竞争
  • 上下文切换

1.4 区分用户态与内核态 CPU

pidstat -p 12345 -u -h 1 5 
字段含义
%usrSQL 计算
%system内核消耗
%CPU总占用

第二阶段:系统层面排查

确认 mysqld 占 CPU 后,需要排除 操作系统导致的性能下降

2.1 上下文切换检查

vmstat 1 5 

重点字段:

字段含义
cs上下文切换
in中断次数

判断:

  • 正常:几千/s
  • 异常:> 20000/s

原因:

  • 线程过多
  • 锁竞争
  • CPU 抢占

进一步:

pidstat -w -p 12345 1 5 

关注:

  • cswch/s
  • nvcswch/s

2.2 内存与 Swap 检查

free -m
vmstat 1 5

关键字段:

字段含义
siswap in
soswap out

⚠️ si/so != 0 = 严重问题

影响:

  • CPU sy 飙升
  • 数据库性能断崖下降

优化:

  • 增内存
  • 调整 buffer pool
  • swapoff -a

2.3 网络连接检查

netstat -an | grep ESTABLISHED | wc -l
netstat -an | grep TIME_WAIT | wc -l
ss -ant | grep :3306 | wc -l

判断:

现象含义
ESTABLISHED 高连接池失效
TIME_WAIT 高短连接风暴

优化:

  • 使用连接池
  • tcp_tw_reuse

2.4 磁盘 I/O 与 CPU 关联

iostat -x -k 1 5 

关注:

字段判断
%util接近100% = 饱和
await>10ms = 慢盘

若同时:

  • wa 高
  • %util 高

➡ CPU 是被动等待。

2.5 NUMA 架构检查

numactl --hardware
dmesg | grep -i numa

问题:

CPU 与内存跨节点访问

建议:

numactl --interleave=all /usr/sbin/mysqld 

2.6 硬中断检查

watch -n 1 'cat /proc/interrupts | grep -E "CPU|eth|nvme|sda"' 

如果某 CPU 中断暴涨:

➡ IRQ 未均衡

解决:

irqbalance 

第一、二阶段总结

检查项命令异常
CPUtopus/wa 高
线程top -H单线程100%
上下文vmstatcs 高
Swapvmstatsi/so>0
网络ssTIME_WAIT 多
NUMAnumactl未绑定

第三阶段:MySQL 层面排查(核心阶段)

当系统层无异常:

问题几乎一定在 SQL 或 MySQL 内部机制

3.1 实时会话分析(抓现行)

SELECT ID, USER, HOST, DB, COMMAND, TIME, STATE, INFO
FROM information_schema.PROCESSLIST
WHERE COMMAND != 'Sleep'
ORDER BY TIME DESC
LIMIT 20;

STATE 含义

状态含义
Sending data全表扫描
Sorting result排序
Creating tmp table临时表
Waiting for lock锁竞争
PurgingUndo 清理

OS 线程关联(8.0)

通过:

performance_schema.threads 

关联:

  • PROCESSLIST_ID
  • THREAD_OS_ID

3.2 慢查询分析(历史问题)

开启:

SET GLOBAL slow_query_log='ON';
SET GLOBAL long_query_time=0.1;
SET GLOBAL log_queries_not_using_indexes='ON';

mysqldumpslow

mysqldumpslow -s t -t 10 slow.log 

pt-query-digest(推荐)

pt-query-digest slow.log 

关注:

  • Rows examine
  • Response time

3.3 状态指标分析

线程

SHOW STATUS LIKE 'Threads_running'; 

规则:

Threads_running ≤ CPU 核心数

临时表

SHOW STATUS LIKE 'Created_tmp%'; 

磁盘临时表高 ⇒ SQL 或 tmp_table_size 问题。

Buffer Pool 命中率

计算:

1 - reads / read_requests 

目标:

≥ 99%

3.4 锁与事务分析

SHOW ENGINE INNODB STATUS\G 

关注:

  • TRANSACTIONS
  • SEMAPHORES

大量 spin/wait ⇒ 锁竞争。

SELECT * FROM sys.innodb_lock_waits; 

检查:

  • 长事务
  • DDL 阻塞

3.5 执行计划分析(最终定位)

EXPLAIN FORMAT=JSON SELECT ...

关键字段:

字段危险信号
typeALL
keyNULL
rows极大
ExtraUsing filesort
ExtraUsing temporary

常见索引失效

  1. 违反最左前缀
  2. 函数计算
  3. 隐式类型转换
  4. %abc 模糊查询

3.6 Performance Schema 深度分析

SELECT EVENT_NAME, COUNT_STAR, SUM_TIMER_WAIT
FROM performance_schema.events_statements_summary_by_global_by_event_name
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 10;

实时:

SELECT *
FROM sys.session
ORDER BY current_statement_latency DESC;

第三阶段决策表

现象原因方案
单 SQL 慢全表扫描建索引
多 SQL 快并发高限流
tmp 表高排序调内存
Buffer miss内存小调 BP
锁等待长事务拆事务
Purging写入多调 purge

推荐排查顺序(实战经验)

① SHOW PROCESSLIST
        ↓
② Threads_running
        ↓
③ Slow Log
        ↓
④ EXPLAIN

以上就是MySQL CPU飙高排查的全流程指南的详细内容,更多关于MySQL CPU飙高排查的资料请关注脚本之家其它相关文章!

相关文章

  • 分析MySQL中索引引引发的CPU负载飙升的问题

    分析MySQL中索引引引发的CPU负载飙升的问题

    这篇文章主要介绍了分析MySQL中索引引引发的CPU负载飙升的问题,文中提到了独立索引所带来的巨大CPU负担,以提醒在MySQL中使用索引要注意CPU负载的问题,需要的朋友可以参考下
    2015-05-05
  • MySQL分库分表的几种方式

    MySQL分库分表的几种方式

    这篇文章主要介绍了MySQL分库分表的几种方式,分库分表方案是对关系型数据库数据存储和访问机制的一种补充,下文更多相关介绍需要的小伙伴可以参考一下
    2022-04-04
  • 详解MySQL批量入库的几种方式

    详解MySQL批量入库的几种方式

    本文主要介绍了详解MySQL批量入库的几种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-02-02
  • 详解 MySQL中count函数的正确使用方法

    详解 MySQL中count函数的正确使用方法

    这篇文章主要介绍了 MySQL中count函数的正确使用方法,帮助大家更好的理解和使用MySQL数据库,感兴趣的朋友可以了解下。
    2020-11-11
  • mysql 8.0.13 安装配置方法图文教程

    mysql 8.0.13 安装配置方法图文教程

    这篇文章主要为大家详细介绍了mysql 8.0.13 安装配置方法图文教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-11-11
  • MySQL窗口函数 OVER()全解析

    MySQL窗口函数 OVER()全解析

    MySQL窗口函数是用于在查询结果集中执行计算的强大工具,它们可以对一组行(窗口)进行计算,并为每一行返回一个值,而不会减少行数,本文给大家介绍MySQL窗口函数 OVER()的相关知识,感兴趣的朋友跟随小编一起看看吧
    2025-12-12
  • SQL使用ROW_NUMBER() OVER函数生成序列号

    SQL使用ROW_NUMBER() OVER函数生成序列号

    这篇文章主要介绍了SQL使用ROW_NUMBER() OVER函数生成序列号,ROW_NUMBER()从1开始,为每一条分组记录返回一个数字,下面文章内容具有一定的参考价值,需要的小伙伴可以参考一下
    2021-12-12
  • mysql踩坑之limit与sum函数混合使用问题详解

    mysql踩坑之limit与sum函数混合使用问题详解

    这篇文章主要给大家介绍了关于mysql踩坑之limit与sum函数混合使用问题的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用mysql具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-06-06
  • MySQL存储全角字符和半角字符的区别

    MySQL存储全角字符和半角字符的区别

    这篇文章主要介绍了MySQL存储全角字符和半角字符的区别的相关资料,需要的朋友可以参考下
    2017-05-05
  • Mysql删除重复数据通用SQL的两种方法

    Mysql删除重复数据通用SQL的两种方法

    本文主要介绍了Mysql删除重复数据通用SQL的两种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-08-08

最新评论