症状会一起出现:网站慢得像爬,top 显示 mysqld 或 mariadbd 排在列表最前面,有时应用还会报告 “Too many connections”。无论是 MySQL CPU 占用过高还是 MariaDB CPU 占用过高,原因很少是服务器太小。更常见的情况是少数几条查询做了远超应有的工作,其他一切都在它们后面排队。本指南针对 MySQL 8.4 和 MariaDB 11 等当前版本,逐步演示诊断过程,从第一次实时查看直到持久的修复。
第 1 步:查看此刻 MySQL CPU 占用过高的原因
用命令行客户端连接(在 MariaDB 上叫 mariadb),然后运行 SHOW FULL PROCESSLIST。每一行是一个连接:其当前语句已经运行了多久、状态以及完整的查询文本。规律很快就会显现:
- 同一条查询出现几十份,每份运行数秒:一条代价高昂的查询遇上了正常流量。
- 许多连接处于 Sleep 状态:应用打开了连接却没有关闭,或者它的连接池过大。
- 出现 “Waiting for table metadata lock” 之类的状态:某次结构变更或某个长事务正在阻塞其他所有人。
- 许多行处于排序和临时表状态:没有合适的索引就进行分组或排序。
两个状态计数器让画面更完整。Threads_running 显示此刻有多少查询正在执行,Max_used_connections 显示自上次重启以来的峰值。一台只有几个 CPU 核心却有几十个运行线程的服务器,是被查询压垮的,而不是被访客压垮的。
第 2 步:开启 MySQL 慢查询日志
实时快照显示的是危机;MySQL 慢查询日志显示的是规律。开启方法是把 slow_query_log 设为 ON,并先把 long_query_time 设为约一秒,待最严重的问题解决后再降低阈值。两者都可以在运行时更改,并写入服务器配置文件使之永久生效。MariaDB 使用相同的变量名,并在其慢查询日志概述中解释了这些选项。
让日志在几个有代表性的繁忙日子里持续运行,然后进行汇总。mysqldumpslow(在 MariaDB 上是 mariadb-dumpslow)会把相似的语句归为一组,Percona Toolkit 中的 pt-query-digest 则给出更详细的排名。请按总耗时排序,而不是按单次最慢的查询:一条耗时 0.2 秒却在每次页面访问时都运行的语句,代价远高于夜间报表。
第 3 步:修复真正重要的查询
对列表顶部的每条查询,运行 EXPLAIN,看优化器打算怎么做。通常的慢查询修复属于下面之一:
- 缺少索引或索引不合适。在大表上进行全表扫描(显示为 type ALL),而在被过滤和排序的列上建立复合索引就能直接找到这些行。
- 在已建索引的列上使用函数,例如在 WHERE 子句中把时间戳列包在日期函数里,这会使索引无法使用。把条件改写成范围即可解决。
- LIKE 搜索中的前导通配符,任何普通索引都帮不上忙。真正的解决办法是全文索引或搜索服务。
- 同一条小查询每个页面重复数百次,常见于插件和应用循环,更适合用应用中的缓存来解决。
请先在数据库副本上测试索引的更改。每个索引都会加快某些读取,但也会给每次插入和更新增加工作量,而在非常大的表上创建索引,在创建期间可能会使其变慢。
为什么 “Too many connections” 通常只是症状
这个错误意味着所有允许的连接都已用完。MySQL 和 MariaDB 默认的 max_connections 都是 151,调高它很诱人。但每个连接都需要内存,而在相同的 CPU 核心上同时运行更多查询,只会让每一条都更慢。请转而寻找连接过多的原因:
- 缓慢的查询一直占着连接,这就回到了第 3 步。
- PHP-FPM 工作进程或应用线程多于数据库能同时服务的数量。Web 层的规模应当让其峰值落在 max_connections 之内,并为管理留出余量。
- 持久连接或过大的连接池让空闲连接开着数小时,这由 wait_timeout 和应用的连接池设置控制。
配置检查与 MariaDB 性能调优
查询得到控制之后,再检查决定数据库服务器要多辛苦工作的设置。InnoDB 缓冲池应当容纳经常使用的数据,让读取来自内存而不是磁盘。溢出到磁盘的临时表会体现在 Created_tmp_disk_tables 计数器中。这些检查是 MySQL 和 MariaDB 性能审查的核心。查询缓存不是解决办法:MySQL 8 已将其移除,而 MariaDB 出厂时将其禁用,因为它在繁忙的服务器上会成为争用点。对于短连接很多的服务器,做 MariaDB 性能调优时值得看看线程池。如果您仍在运行 MySQL 8.0,请注意 Oracle 已于 2026 年 4 月结束对它的支持;8.4 是大多数 8.0 服务器升级的长期支持版本,而升级是重新检查查询计划的好时机。
常见问题:MySQL CPU 占用过高
CPU 占用高一定是数据库的问题吗?
不一定。如果 mysqld 或 mariadbd 没有排在进程列表的前面,就应转而检查 PHP、Web 服务器或某个备份任务。当数据库进程占据主导地位,且进程列表显示查询正在堆积时,数据库才很可能是罪魁祸首。
CPU 被占满时应该重启 MySQL 吗?
重启会暂时清空队列,但同样的查询会随着流量回来,而且重启还会清空缓冲池,所以在它重新预热之前服务器会更慢。请先保存 SHOW FULL PROCESSLIST 的输出,以免证据丢失。
可以安全地终止长时间运行的查询吗?
使用进程列表中的连接 ID 执行 KILL QUERY,会停止该语句并保持连接打开,而 KILL 会结束连接。停止一次大的写入可能要花一些时间,因为它的更改要被回滚,而且这并不能解决原因,所以在终止之前请记下该查询。
如果洛杉矶(Los Angeles)或其他地方的数据库持续过热,我们的 MySQL 和 MariaDB 数据库优化服务会审查慢查询日志、索引和配置,而大部分耗时花在几个繁忙日子里收集慢日志上,而不是更改本身。如果 Web 服务器是问题的另一半,请参阅我们的 Apache Web 服务器优化服务。请联系我们,告诉我们您的数据库版本以及变慢发生的时间。




