Linux服务器上MySQL CPU使用率过高问题排查与定位

文章目录

    • 一、CPU高负载常见成因分析
      • 1.1 全表扫描与索引缺失
      • 1.2 复杂计算与临时表
      • 1.3 锁竞争与线程上下文切换
      • 1.4 查询优化器误判
      • 1.5 硬件资源瓶颈
    • 二、操作系统级初步定位
      • 2.1 使用top定位MySQL进程
      • 2.2 用pidstat分析线程级CPU
      • 2.3 vmstat分析系统负载
    • 三、数据库层深度诊断
      • 3.1 SHOW PROCESSLIST锁定问题SQL
      • 3.2 EXPLAIN分析执行计划
      • 3.3 SHOW PROFILE分析阶段耗时
    • 四、实战案例:订单查询模块CPU飙升排查
      • 4.1 问题现象
      • 4.2 操作系统层排查
      • 4.3 数据库层诊断
      • 4.4 优化方案与验证
    • 五、预防措施与日常监控
      • 5.1 建立索引优化机制
      • 5.2 开启慢查询日志
      • 5.3 自动化监控脚本
    • 总结

在Linux服务器环境中,MySQL数据库出现CPU使用率过高是常见的性能故障。本文将结合实际排查流程,通过具体工具和案例,详细讲解如何定位与分析MySQL CPU高负载问题。内容涵盖常见成因分析、操作系统级监控、数据库层诊断及实战优化案例,全程以实操为导向,避免理论堆砌。

一、CPU高负载常见成因分析

1.1 全表扫描与索引缺失

当查询语句未命中索引时,MySQL会触发全表扫描(type: ALL),导致大量CPU消耗在磁盘数据读取与过滤上。典型场景包括:

  • WHERE条件字段未建立索引
  • 索引因字段类型不匹配、函数运算等原因失效

案例:某电商订单表查询语句SELECT * FROM orders WHERE create_time > '2023-01-01'未在create_time字段建索引,执行时扫描1000万条记录,CPU使用率飙升至80%。

1.2 复杂计算与临时表

包含大量计算函数(如COUNT(DISTINCT)GROUP_CONCAT)或隐式创建临时表的查询(如EXPLAIN结果中Extra包含Using temporary),会消耗大量CPU进行数据处理。例如:

-- 含DISTINCT和分组的复杂查询
SELECT user_id, COUNT(DISTINCT product_id) AS cnt 
FROM order_items 
GROUP BY user_id 
HAVING cnt > 10;

1.3 锁竞争与线程上下文切换

InnoDB行锁竞争或表锁冲突会导致线程频繁等待锁释放,伴随大量上下文切换(Context Switch)。通过vmstat工具查看cs(上下文切换次数)值,若远超正常水平(如每秒>10万次),需排查锁问题:

# 每2秒采样一次,共5次
vmstat 2 5

1.4 查询优化器误判

MySQL优化器可能因统计信息过时(如未执行ANALYZE TABLE),选择非最优执行计划。例如误判扫描行数,导致放弃索引改用全表扫描:

-- 执行计划显示扫描100行,实际扫描10万行
EXPLAIN SELECT * FROM users WHERE status = 'active';

1.5 硬件资源瓶颈

当CPU核心数不足或内存带宽受限,即使查询优化良好,也可能出现CPU瓶颈。需通过nproc查看CPU核心数,free -h检查内存使用情况:

# 查看逻辑CPU核心数
nproc --all

二、操作系统级初步定位

2.1 使用top定位MySQL进程

通过top命令实时监控系统进程,按shift + p以CPU使用率排序,确认mysqld进程是否为CPU高占用源头:

top -c  # -c参数显示完整命令行

关键信息

  • %CPU:进程占用CPU百分比(多核CPU需按核心数折算,如8核CPU中某进程%CPU达160%表示占用2个核心)
  • COMMAND:显示当前执行的SQL片段(若开启show_compatibility_56参数)

案例:发现mysqld进程%CPU持续在150%(8核系统),命令行显示SELECT * FROM logs WHERE user_id = 123,初步判断为该查询引发。

2.2 用pidstat分析线程级CPU

pidstat可按线程维度统计CPU使用情况,定位具体线程ID(TID):

# 监控mysqld进程(PID=12345)的线程,每2秒采样一次
pidstat -t -p 12345 2

输出解读

Linux 5.4.0-105-generic (server01)   2024-12-10 14:30:00   _x86_64_    (8 CPU)14:30:00  UID       PID   TID    %usr %system  %guest   %wait    %CPU   CPU  Command
14:30:02    1001    12345 12346  15.00   5.00    0.00    0.00   20.00     1  mysqld
14:30:02    1001    12345 12347  18.00   7.00    0.00    0.00   25.00     3  mysqld
  • TID:线程ID(需转换为16进制,用于后续SHOW PROCESSLIST匹配)
  • %CPU:该线程占用CPU百分比

2.3 vmstat分析系统负载

通过vmstat查看系统整体负载与CPU状态:

vmstat -n 2 5  # 每秒采样,共5次

关键指标

  • r(运行队列长度):等待CPU资源的进程数,若持续大于CPU核心数2倍以上,表明CPU瓶颈
  • us(用户态CPU):应用程序消耗CPU占比
  • sy(系统态CPU):内核操作消耗CPU占比
  • cs(上下文切换):每秒上下文切换次数

案例:发现r=6(8核CPU),us=70%sy=25%cs=80000/s,判断为用户态应用导致CPU高负载,伴随大量上下文切换。

三、数据库层深度诊断

3.1 SHOW PROCESSLIST锁定问题SQL

通过SHOW PROCESSLIST查看当前活跃线程,重点关注:

  • State:线程状态(如Sending dataCopying to temporary table
  • Time:持续执行时间(秒)
  • Info:具体SQL语句
SHOW PROCESSLIST;

输出示例

+-----+------+-----------+------+---------+------+-------+----------------------------------------+
| Id  | User | Host      | db   | Command | Time | State | Info                                   |
+-----+------+-----------+------+---------+------+-------+----------------------------------------+
| 123 | root | localhost | test | Query   | 120  | Sending data | SELECT * FROM large_table WHERE id < 100000 |
| 124 | root | localhost | test | Sleep   | 3600 |       | NULL                                   |
+-----+------+-----------+------+---------+------+-------+----------------------------------------+
  • Time较长(如>60秒)的线程,可通过KILL [Id]终止
  • 记录Id对应的TID(需通过SELECT CONNECTION_ID();获取当前线程ID与操作系统TID的映射关系)

3.2 EXPLAIN分析执行计划

SHOW PROCESSLIST中定位的慢查询,使用EXPLAIN分析执行计划,重点检查:

  • type:是否为低效的ALL(全表扫描)或index(索引全扫描)
  • key:是否使用预期索引
  • rows:预估扫描行数是否与实际数据量匹配
  • Extra:是否包含Using temporaryUsing filesort等性能损耗标记

案例:慢查询SELECT * FROM orders WHERE status = 'paid' AND create_time > '2024-01-01'的执行计划:

EXPLAIN SELECT * FROM orders 
WHERE status = 'paid' AND create_time > '2024-01-01';
+----+-------------+--------+------------+------+---------------+------+---------+------+--------+----------+----------------------------------------------+
| id | select_type | table  | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra                                        |
+----+-------------+--------+------------+------+---------------+------+---------+------+--------+----------+----------------------------------------------+
|  1 | SIMPLE      | orders | NULL       | ALL  | idx_status    | NULL | NULL    | NULL | 100000 |    10.00 | Using where; Using temporary; Using filesort |
+----+-------------+--------+------------+------+---------------+------+---------+------+--------+----------+----------------------------------------------+

问题定位

  • type=ALL:全表扫描
  • Extra包含Using temporaryUsing filesort:触发临时表和文件排序
  • 未使用statuscreate_time索引

3.3 SHOW PROFILE分析阶段耗时

通过SHOW PROFILE获取SQL执行各阶段耗时,定位瓶颈环节:

-- 开启profiling
SET profiling = 1;-- 执行目标SQL
SELECT * FROM orders WHERE ... ;-- 获取最近一次查询的profile
SHOW PROFILE FOR QUERY (SELECT query_id FROM information_schema.PROFILING ORDER BY query_id DESC LIMIT 1);

典型输出

+----------------------+----------+------------+-------------+
| Status               | Duration | CPU_user   | CPU_system  |
+----------------------+----------+------------+-------------+
| starting             | 0.00003  | 0.00001    | 0.00001     |
| checking permissions | 0.00001  | 0.00000    | 0.00000     |
| Opening tables       | 0.00002  | 0.00001    | 0.00001     |
| System lock          | 0.00001  | 0.00000    | 0.00000     |
| optimizing           | 0.00005  | 0.00003    | 0.00002     |
| statistics           | 0.00012  | 0.00008    | 0.00004     |
| preparing            | 0.00004  | 0.00002    | 0.00002     |
| executing            | 0.00003  | 0.00001    | 0.00001     |
| Sending data         | 2.56789  | 1.89023    | 0.67766     |
| end                  | 0.00002  | 0.00001    | 0.00001     |
+----------------------+----------+------------+-------------+
  • Sending data阶段耗时占比超70%,通常为结果集过大或网络传输瓶颈
  • optimizing阶段耗时高,可能为查询优化器计算复杂,需更新统计信息或重构查询

四、实战案例:订单查询模块CPU飙升排查

4.1 问题现象

某电商平台订单查询页面响应缓慢,监控显示Linux服务器MySQL进程CPU使用率持续达180%(8核系统),topmysqld进程%CPU为180%,COMMAND显示正在执行订单列表查询。

4.2 操作系统层排查

  1. top确认进程

    top -c | grep mysqld
    # 输出显示PID=23456,%CPU=180%,命令行包含"SELECT o.*, u.name FROM orders o JOIN users u ON o.user_id=u.id WHERE o.status='paid'"
    
  2. pidstat线程分析

    pidstat -t -p 23456 2
    # 发现TID=23458(16进制为0x5BCA)和TID=23459(0x5BCB)两个线程各占90% CPU
    
  3. vmstat系统负载

    vmstat 2 5
    # r=4(小于8核*2),us=85%,sy=10%,cs=60000/s,判断为用户态SQL查询导致
    

4.3 数据库层诊断

  1. SHOW PROCESSLIST定位线程

    SHOW PROCESSLIST;
    # 找到Id=1234对应的线程,User=app_user,Info=目标查询语句,Time=156秒
    
  2. EXPLAIN执行计划分析

    EXPLAIN SELECT o.*, u.name FROM orders o 
    JOIN users u ON o.user_id=u.id 
    WHERE o.status='paid' AND o.create_time>'2024-01-01';
    
    +----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+---------------------------------------------+
    | id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra                                       |
    +----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+---------------------------------------------+
    |  1 | SIMPLE      | o     | NULL       | ALL  | idx_status    | NULL | NULL    | NULL | 100000 |    10.00 | Using where; Using temporary; Using filesort |
    |  1 | SIMPLE      | u     | NULL       | eq_ref| PRIMARY       | PRIMARY| 4       | o.user_id | 1      |   100.00 |                                             |
    +----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+---------------------------------------------+
    

    问题点

    • 主表orders未使用索引,全表扫描10万条记录
    • 触发临时表(Using temporary)和文件排序(Using filesort
  3. SHOW PROFILE阶段耗时

    SHOW PROFILE FOR QUERY ...;
    # Sending data阶段耗时2.3秒,占总耗时92%,表明大量数据传输
    

4.4 优化方案与验证

  1. 添加复合索引

    ALTER TABLE orders ADD INDEX idx_status_create_time (status, create_time);
    
  2. 优化查询语句

    -- 避免SELECT *,只查询必要字段
    SELECT o.order_id, o.total_amount, u.name 
    FROM orders o 
    JOIN users u ON o.user_id=u.id 
    WHERE o.status='paid' AND o.create_time>'2024-01-01' 
    ORDER BY o.create_time DESC 
    LIMIT 20;
    
  3. 验证执行计划

    EXPLAIN SELECT ...;
    # type变为range,key使用idx_status_create_time,rows预估1000条,Extra移除临时表和文件排序
    
  4. CPU使用率验证

    top -c | grep mysqld
    # %CPU降至20%,查询响应时间从156秒缩短至0.3秒
    

五、预防措施与日常监控

5.1 建立索引优化机制

  • 定期通过pt-index-usage(Percona Toolkit工具)分析未使用索引
  • 对高频查询执行EXPLAIN检查执行计划

5.2 开启慢查询日志

配置long_query_time=1,通过mysqldumpslow分析慢查询分布:

# 按查询时间排序,取前10慢查询
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log

5.3 自动化监控脚本

编写Shell脚本定时采集CPU、线程状态等指标:

#!/bin/bash
DATE=$(date +%Y-%m-%d_%H:%M:%S)
CPU_USAGE=$(top -bn1 | grep 'Cpu(s)' | awk '{print $2}')
THREADS=$(mysql -e "SHOW STATUS LIKE 'Threads_running';" | awk '{print $2}')
echo "$DATE,$CPU_USAGE,$THREADS" >> mysql_monitor.log

总结

MySQL CPU使用率过高的排查需遵循“操作系统层定位进程→数据库层分析SQL→执行计划优化→效果验证”的流程。通过toppidstat等工具锁定问题进程,利用SHOW PROCESSLISTEXPLAINSHOW PROFILE深入分析SQL执行细节,结合索引优化、查询重构等手段解决性能瓶颈。实际操作中需注意多维度数据关联分析,避免单一工具误判,同时建立常态化监控机制预防问题复现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/pingmian/84651.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java解析前端传来的Unix时间戳

在Java中&#xff0c;前端传递的 1749571200000 是一个 Unix时间戳&#xff08;毫秒级&#xff09;&#xff0c;表示自1970年1月1日00:00:00 UTC以来经过的毫秒数。以下是两种常见的解析方式&#xff08;推荐使用Java 8的java.time API&#xff09;&#xff1a; 方法1&#xff…

error report

build/X86_VI_hammer_GPU/mem/ruby/network/garnet/fixed-pipeline/OutputUnit_d.cc: In member function ‘int OutputUnit_d::getVCBufferOccupancy(int)’: build/X86_VI_hammer_GPU/mem/ruby/network/garnet/fixed-pipeline/OutputUnit_d.cc:135:40: error: no matching fu…

本地部署模型 --vLLM + Docker 部署+封装接口

vLLM的介绍 vLLM的核心特性&#xff1a; 最先进的服务吞吐量 使用PageAttention高效管理注意力键和值的内存 量化&#xff1a;GPTQ&#xff0c;AWQ&#xff0c;INT4&#xff0c;INT8和FP8 VLLM的灵活性和易用性体现在以下方面&#xff1a; 具有高吞吐量服务以及各种解码算法…

每日一博 - JWT 安全实战指南

文章目录 Pre引言背景与原理简介核心安全挑战传输层安全实践签名算法与密钥管理Header 与 Claims 严格校验Token 生命周期管理存储与前端实践抗攻击措施日志与监控附加增强与高级方案小结与建议后续方向 引言&#xff1a;阐述 JWT 的流行与安全重要性背景与原理简介&#xff1a…

403 Access Denied Tomcat managerapp

提示 403 Access Denied You are not authorized to view this page. By default the Manager is only accessible from a browser running on the same machine as Tomcat. If you wish to modify this restriction, you’ll need to edit the Manager’s context.xml file.…

工业镜头选型讲解

B站 &#xff1a;道传科技上位机 观看教程 一、工业镜头介绍 镜头的主要作用是 将目标成像在图像传感器的光敏面上。 下图左一的型号为 焦距 50mm 最大光圈为F1.6 镜头的像面尺寸为2/3英寸&#xff08;最大能够兼容CCD芯片尺寸&#xff09; 二、工业镜头的分类 镜头的…

重构技术奇点的路径:三智双融认知大飞跃

结合三智双融理论认知大飞跃框架重构技术奇点的路径 构建一个三维修订框架&#xff1a;首先分析融智学视域下的奇点渗透本质&#xff0c;然后按时间线逐年修订预言并补充融智学维度&#xff0c;最后提出人机共生的实践路径。考虑设计表格对比原预言与修订后的差异&#xff0c;突…

LabVIEW利用Monte Carlo 工业数据模拟应用

基于LabVIEW 平台&#xff0c;结合 NI 工业级硬件构建 Monte Carlo 模拟系统&#xff0c;实现工业传感器数据不确定性分析与设备故障概率预测。通过图形化编程架构与高性能硬件协同&#xff0c;解决复杂工业场景下的随机问题量化分析需求&#xff0c;适用于智能制造、能源监控等…

2025年渗透测试面试题总结-天翼电子公司[社招]安全运营岗(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 天翼电子商务有限公司[社招]安全运营岗 1. Web服务加固方案 2. IAST技术解析 3. SCA&#xff08;软件成分…

Java NIO详解:新手完全指南

文章目录 1. NIO简介1.1 NIO的核心优势1.2 NIO的适用场景 2. NIO与IO的对比2.1 代码对比示例2.1.1 传统IO读取文件2.1.2 NIO读取文件 3. NIO核心组件3.1 Buffer&#xff08;缓冲区&#xff09;3.2 Channel&#xff08;通道&#xff09;3.3 Selector&#xff08;选择器&#xff…

webgl(three.js 与 cesium 等实例应用)之浏览器渲染应用及内存释放的关联与应用

文章目录 WebGL 概念1. 纹理&#xff08;Texture&#xff09;&#x1f4cc; 概念&#xff1a;&#x1f9e9; 应用方向&#xff1a;&#x1f4a1; 示例代码&#xff08;加载一张图片作为纹理&#xff09;&#xff1a; 2. 缓冲区&#xff08;Buffer&#xff09;&#x1f4cc; 概念…

黑马点评【缓存】

目录 一、为什么要使用缓存 二、添加商户缓存 1.缓存的模型和思路 2.代码 3.缓存更新策略 Redis内存淘汰机制&#xff1a; 3.1 被动淘汰策略&#xff08;不主动淘汰&#xff0c;仅在查询时触发&#xff09; 3.2 主动淘汰策略&#xff08;主动扫描内存&#xff0c;按规则…

【地图服务限制范围】

根据你提供的 eb_service_area 表结构&#xff0c;其中有两个字段与地理坐标相关&#xff1a;latlng 和 limit_latlng。这两个字段分别用于存储服务范围区域的坐标和限制区域的坐标。下面是对这两个字段的具体分析以及如何使用它们来定义执行范围。 字段分析 latlng&#xff0…

python数据结构和算法(1)

数据结构和算法简介 数据结构&#xff1a;存储和组织数据的方式&#xff0c;决定了数据的存储方式和访问方式。 算法&#xff1a;解决问题的思维、步骤和方法。 程序 数据结构 算法 算法 算法的独立性 算法是独立存在的一种解决问题的方法和思想&#xff0c;对于算法而言&a…

Linux操作系统-性能优化

1. 基础工具 top / htop top # 实时查看CPU、内存、进程 htop # 增强版&#xff08;支持鼠标操作&#xff09; 关键指标&#xff1a;%CPU&#xff08;CPU占用&#xff09;、%MEM&#xff08;内存占用&#xff09;、LOAD AVERAGE&#xff08;系统负载&#…

如何彻底解决缓存击穿、缓存穿透、缓存雪崩

一、缓存击穿 成因&#xff1a;缓存击穿通常发生在某个热点数据失效或清空后&#xff0c;大量请求同时涌入后端数据库&#xff0c;导致数据库崩溃或宕机。 解决方案&#xff1a; 互斥锁&#xff1a;在获取数据时&#xff0c;使用分布式锁&#xff08;如Redis的分布式锁&…

JDK 8、JDK 17和JDK 19综合对比分析

JDK 8、JDK 17和JDK 19在性能、特性、易用性及普及性等方面的综合对比分析&#xff0c;结合了各版本的核心改进和实际应用场景 目录 ⚡ 一、性能对比 ✨ 二、语言与特性演进 &#x1f6e0;️ 三、API与功能增强 &#x1f3af; 四、易用性改进 &#x1f4ca; 五、市场普及…

Vue-理解 vuex

一、前言 在开发中大型 Vue 应用时&#xff0c;我们常常会遇到多个组件之间共享数据、通信复杂的问题。例如&#xff1a; 多个组件需要访问同一个用户信息&#xff1b;组件之间需要传递状态或事件&#xff1b;数据变更需要同步更新多个组件&#xff1b; 这时&#xff0c;Vue…

【209】VS2022 C++对排好序的vector使用二分查找算法的例子

本文介绍了如何对已经排序的 vector 进行二分法查找。 首先&#xff0c;我们先看一下存储数据的类&#xff0c;我们假设所有数据的 id 是唯一的&#xff1a; DataItem.h #pragma once #include<string>namespace zc {class DataItem{public:int m_id;std::string m_na…

ABAP 上传 excel 报表

&#xff08;1&#xff09;先在屏幕上增加上传文件的按钮 "屏幕选择条件" SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-001. PARAMETERS : p_source LIKE rlgrap-filename . SELECTION-SCREEN END OF BLOCK b1. 你会发现&#xff0c;上面的代码只…