数据库服务器CPU过高不是玄学,绝大多数情况下是慢查询、索引失效或锁等待在作祟,直接定位TOP SQL并针对性优化,比盲目加CPU核数管用得多。下面这套排查路径和操作手法,是我处理过上百台“卡死”数据库后总结出来的,照着做,能解决八成以上问题。
数据库服务器cpu过高怎么办:先分清是“真忙”还是“假忙”
很多人一看到监控面板上CPU飙到90%就慌了,第一步就想着加配置,但动手之前,先花两分钟搞清楚一件事:CPU是持续高,还是脉冲式高。
持续高位运行,说明数据库有长期吃满资源的任务在跑,比如全表扫描、无限制的笛卡尔积连接,或者后台正在做索引重建,脉冲式高峰则往往对应业务高峰期的瞬时并发,比如每天早上九点的批量打卡、月末的报表集中生成。
另外一个容易忽略的点:CPU高不一定是数据库进程本身吃掉的,登录服务器跑一下top,按CPU排序,看看排在前面的是不是mysqld或者sqlservr进程,如果是一个叫java或者php-fpm的进程占用最高,那问题出在应用层,数据库只是被连累的,这种情况下你去优化数据库索引,方向就错了。
业内专家指出,相当一部分“数据库CPU告警”最终定位下来是应用代码闹的乌龙连接池配置过大、循环里发了上万次查询、Redis缓存失效击穿了数据库。
数据库cpu飙高排查步骤:从全局到单条SQL的六步走
确认了是数据库进程在烧CPU,接下来按顺序执行下面这套动作,每一步都有明确的验证方法。
- 看进程状态:执行
show processlist;(MySQL)或sp_who2(SQL Server),重点看State列和Time列,如果大量线程卡在Sending data、Copying to tmp table、Sorting result,那就是查询在拖后腿。 - 抓TOP SQL:MySQL 5.7以上可以用
performance_schema,直接查events_statements_summary_by_digest表,按SUM_TIMER_WAIT排序取前五条,SQL Server则从sys.dm_exec_query_stats里取total_worker_time最大的几条。 - 看执行计划:拿到TOP SQL后,前面加
EXPLAIN(MySQL)或SET SHOWPLAN_ALL ON(SQL Server),重点看有没有type=ALL(全表扫描)、rows预估是否离谱、Extra里有没有Using filesort或Using temporary。 - 检查索引命中:执行计划里
key字段如果为NULL,说明这条SQL没走索引,别急着加索引,先看WHERE条件的字段有没有做函数运算或隐式类型转换比如WHERE phone = 13800000000,但字段是varchar类型且存的是带区号的字符串,这种加索引也没用。 - 看锁等待:
show open tables where in_use > 0;查看是否有表锁堆积,MySQL的sys.innodb_lock_waits、SQL Server的sys.dm_tran_locks都能直接看到谁堵了谁。 - 确认硬件瓶颈是否为假象:用
vmstat 1 5看cs(上下文切换)列和in(中断)列,如果us(用户态)不高但sy(系统态)很高,问题可能出在网卡中断或者多线程调度上,而不是SQL本身。
这套流程走下来,慢查询基本无所遁形,多数情况下你会发现,80%的CPU开销来自20%的烂SQL,把这几条优化好,CPU立刻回落。
mysql占用cpu过高如何解决:一个真实业务场景的优化过程
举个实际案例,某电商后台的订单列表页一到下午就卡,CPU持续在80%以上,抓出来的TOP SQL长这样:
SELECT FROM orders WHERE create_time BETWEEN '2026-01-01' AND '2026-12-31' AND status = 1 ORDER BY id DESC LIMIT 20;
表面上看没毛病,BETWEEN走范围索引,STATUS也有索引,但执行计划显示rows扫了九十多万行,原因在于create_time上有索引,但筛选出来的数据量太大,MySQL优化器认为全扫比走索引再回表更快,于是选择了ALL。
优化方案分两步:第一步,把(status, create_time)做成联合索引,让过滤先走status缩窄范围;第二步,改SQL为WHERE create_time BETWEEN ... AND ... AND status = 1 ORDER BY create_time DESC,让排序走索引避免filesort,改完以后CPU从85%掉到12%,查询耗时从2.8秒降到40毫秒。
这个场景后续还被客户问过数据库服务器cpu过高 卡死 解决办法,其实核心就一句话:把高频查询用到的WHERE、ORDER BY、GROUP BY字段按顺序放进联合索引,同时避免SELECT 取多余列。
sql server cpu过高排查的独特之处:等待类型才是关键信号
SQL Server和MySQL在排查思路上有差异,MySQL看processlist足够,但SQL Server的CPU问题必须先看等待类型。
登录后执行下面这条语句:
SELECT wait_type, wait_time_ms, waiting_tasks_count FROM sys.dm_os_wait_stats ORDER BY wait_time_ms DESC;
输出结果里如果CXPACKET排在最前面,说明并行查询等待过多,这个问题在SQL Server里很典型:大量低并发查询被分配到多个CPU核并行执行,协调上花的时间比执行本身还长,解决方案是限max degree of parallelism的值,OLTP系统一般建议设为2到4,别设成0(默认用满所有核)。
如果SOS_SCHEDULER_YIELD占大头,那是CPU确实被跑满了,需要进一步查sys.dm_exec_requests看到底哪些请求在消耗,SQL Server 2016以上版本可以直接看sys.dm_db_resource_stats(Azure SQL)或sys.dm_os_schedulers(本地库)。
行业共识认为,SQL Server的CPU排查比MySQL更依赖动态视图,日常巡检时建议把这几个DMV的查询结果做成脚本存下来,出了问题好做对比。
数据库服务器选型与硬件升级建议:什么情况才值得加核
虽然前面说了优先优化SQL,但确实存在纯硬件瓶颈的场景,判断标准很简单:把TOP 10 SQL全部优化完之后,CPU依然在70%以上,且慢查询日志里没有新的烂SQL产生,这时候才考虑升级。
硬件升级方向有三个,优先级从高到低:
- 加内存:如果数据库的缓冲池命中率低于95%,内存就是短板,MySQL的
innodb_buffer_pool_size、SQL Server的max server memory没设置好,再多的CPU核也是白瞎,给多大的内存,看information_schema里的data_length + index_length总和,至少让缓冲池能装下全部热数据。 - 换NVMe SSD:如果
iowait在CPU高的同时也不低,说明磁盘跟不上,普通SATA SSD换成企业级NVMe,随机读写延迟能降低一个数量级。 - 加CPU核数:只在并发特别高、单条SQL已经优化到极限的情况下才有效,而且要注意,核数增加并不会线性提升数据库性能,超过16核以后,MySQL的扩展性曲线明显变平,SQL Server稍好一些但也有限。
还要提一嘴本地部署和云数据库的选择,云厂商的RDS自带监控告警和自动扩容,出问题一键拉高配置,自建数据库的话,数据库服务器多少钱一台这个问题在CPU优化的语境下其实不重要,因为硬件成本通常远低于你排查故障消耗的人工成本有能力的话优先上云。
预防方案:把CPU巅峰压在日常巡检里
解决问题只是第一步,不让它复发才是核心,下面这套日常巡检清单,照着搭起来,比每次都等告警再救火强得多。
- 开启慢查询日志,阈值设1秒,每天分析一次,MySQL用
set global slow_query_log = ON;,SQL Server用sys.dm_exec_query_stats定期快照对比。 - 每周跑一次
pt-query-digest(Percona Toolkit)分析索引使用频率,找出从未被用过的冗余索引并删除,减少写操作开销。 - 监控
Threads_connected(MySQL)和user_connections(SQL Server),设置最大连接数上限,防止连接风暴把CPU打死。 - 大促或月底批量任务前,提前用
EXPLAIN预演核心报表SQL,确认执行计划没有走偏。 - 建立基线:统计正常工作日的CPU均值、峰值、慢查询数量,有了基线,下次CPU再高的时候,你能快速判断是异常还是业务正常增长。
Q&A:围绕数据库服务器cpu过高的高频追问
问:数据库cpu飙高的时候,直接重启数据库有没有用?
重启能暂时缓解症状,如果是因为积累了N个长时间未提交的事务或者内存里的锁出现了混乱,重启确实能立竿见影,但如果根子是烂SQL,重启完业务流量一进来,CPU照样飙回去,而且重启意味着所有连接断开、缓冲池清空,恢复期间会有一次新的性能凹谷,建议先用show processlist抓现场,把TOP SQL记录下来,再考虑重启,连现场都不留就重启,就像电脑蓝屏后不记错误代码直接重装系统,问题大概率还会复现。
问:用了云数据库RDS,CPU告警还能自己做主排查吗?
云数据库通常不给你服务器本身的root权限,但主流的云厂商控制台都提供了性能洞察功能,比如简米云的DAS、酷番云的DBbrain,能看到TOP SQL和会话快照,操作建议是先在控制台启用SQL审计和性能洞察,等下次CPU高的时候去回放那个时间段的请求,云服务商的好处是硬件故障不用你管,但SQL质量的责任还是在应用团队身上,需要注意的是,云数据库的CPU规格是共享物理机上的虚拟核,相邻实例的邻居噪音也可能导致CPU波动,这种场景再多的优化也没用,直接提工单让云厂商排查物理宿主机就行。
数据库服务器CPU高这件事,来的时候很吓人,但逻辑链不长:先确认是不是数据库进程干的,再抓TOP SQL看执行计划,然后针对性优化索引或SQL写法,最后用巡检机制兜底。只要慢查询在掌控之中,CPU就不会失控。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/790602.html


