数据库CPU飙升90%紧急排查:从SQL执行计划到系统资源的系统性诊断 30款热门AI模型一站整合DeepSeek/GLM/Qwen 随心用限时 5 折。 点击领海量免费额度昨天下午一个紧急电话打过来说线上核心业务突然变慢用户投诉激增。登录服务器一看数据库CPU直接飙到90%监控面板一片飘红。团队里最资深的DBA休假了几个开发同学对着监控图面面相觑有人提议“重启试试”有人开始翻看最近上线的代码。这场景太典型了。一条昨天还跑得好好的SQL今天突然成了性能杀手。问题往往不是出在“数据库”这个黑盒本身而是它周围的一切——数据、查询、资源、乃至一个不经意的配置变更——共同作用的结果。排查这种问题需要的不是对某个命令的机械记忆而是一套清晰的、可复现的思考框架。它像侦探破案先确定案发现场现象再寻找线索日志、监控最后锁定真凶根本原因。今天我们就来彻底拆解这个经典面试题背后的实战排查逻辑。它考察的绝不仅仅是几个EXPLAIN或SHOW PROCESSLIST命令而是你能否在高压下用系统化的方法把“感觉慢了”这种模糊描述精准定位到一个可解释、可解决的具体问题上。1. 第一反应稳住阵脚确认问题范围当警报响起CPU 90%时最忌讳的就是盲目行动。你的第一组操作决定了接下来是快速止损还是让问题雪上加霜。1.1 立即获取“现场快照”不要急着去改任何配置或杀进程。首先用最快的速度获取问题发生时的系统状态快照。这相当于刑侦中的保护现场。连接数据库使用具有足够权限的账号如root连接到出问题的数据库实例。如果连接已经非常缓慢考虑从本地或跳板机使用带-h参数的客户端快速连接。查看当前活动会话执行SHOW FULL PROCESSLIST;(MySQL) 或SELECT * FROM pg_stat_activity WHERE state ! idle;(PostgreSQL)。这个命令能立刻告诉你现在有哪些连接每个连接正在执行什么SQLInfo列它们已经运行了多久Time列处于什么状态State列如Sending data,Locked,Creating sort index等关键点立刻寻找那些Time值巨大比如几百秒且State不是Sleep的会话。这些就是最可疑的“嫌犯”。把对应的SQL语句完整记录下来。确认系统负载在数据库服务器上快速运行top或htop命令。确认高CPU消耗的进程确实是数据库服务进程如mysqld,postgres而不是其他进程。同时观察%waI/O等待指标如果也很高说明可能遇到了磁盘瓶颈。注意如果SHOW PROCESSLIST都执行得非常慢说明系统可能已经严重过载。此时可以考虑使用mysqladmin工具或操作系统级别的kill命令终止几个最耗时的查询来救急但务必先记录下它们的ID和SQL以便后续分析。1.2 区分“症状”与“病因”CPU 90%是症状那条跑了5秒的SQL是直接病因。但我们的目标是找到根本病因——为什么同一条SQL昨天和今天的行为天差地别此时你需要建立一个初步的排查假设清单按可能性从高到低排序数据量突变SQL查询的表数据量是否发生了剧增例如夜间批量任务导入大量数据或某个条件过滤失效导致扫描全表。执行计划改变数据库优化器为这条SQL选择的“执行计划”发生了变化导致走了低效的索引或全表扫描。系统资源争用同一时刻有其他重型查询或任务在运行抢占了CPU、内存或I/O资源。锁竞争查询需要访问的数据被其他事务长时间锁定导致查询挂起等待。外部因素服务器本身资源CPU、内存、磁盘出现故障或配置被修改。带着这些假设我们进入下一阶段的深度调查。2. 深度调查剖析那条“变质”的SQL拿到了可疑SQL语句接下来就要像法医一样对它进行解剖。核心工具是数据库提供的执行计划分析命令。2.1 获取并解读执行计划以MySQL为例在测试环境或从线上拉取的慢查询日志中对那条慢SQL执行EXPLAIN或EXPLAIN FORMATJSON获取更详细信息。EXPLAIN SELECT * FROM orders WHERE user_id 123 AND create_date 2023-10-01;你需要重点关注EXPLAIN输出中的这几个关键列列名含义可能的问题信号type访问类型ALL全表扫描是最大的危险信号。理想情况应是const,eq_ref,ref,range。index全索引扫描有时也低效。key实际使用的索引如果这一列为NULL说明没有使用索引。检查是否与你期望的索引一致。rows预估需要扫描的行数这个数字是否巨大比如从几十激增到几百万。这直接关联CPU消耗。Extra额外信息Using filesort文件排序,Using temporary使用临时表通常意味着高开销操作。对比分析是灵魂光看今天的执行计划不够。你需要对比昨天的正常执行计划和今天的异常执行计划。如果公司有慢查询监控平台如Archery, Yearning, pt-query-digest可以从中历史记录。如果没有这提醒了我们建立基线baseline的重要性。假设你发现昨天type是ref使用了索引今天却变成了ALL全表扫描。那么问题就聚焦了为什么优化器不用索引了2.2 追问“为什么不用索引”索引失效是导致SQL“变质”最常见的原因之一。你需要沿着以下线索排查索引是否被误删检查表结构确认预期的索引比如idx_user_id是否还存在。SHOW INDEX FROM orders;字段类型是否匹配WHERE user_id 123字符串和WHERE user_id 123整数可能导致索引失效如果user_id是整型的话。是否对索引列做了计算或函数操作WHERE YEAR(create_date) 2023会导致无法使用create_date上的索引。数据分布是否巨变这是最隐蔽的原因。优化器会根据统计信息如索引的区分度、数据分布直方图来判断使用索引是否划算。如果user_id123的记录昨天只有10条今天因为数据导入变成了10万条优化器可能认为“既然要返回这么多数据不如直接全表扫描更快”从而抛弃索引。检查表统计信息ANALYZE TABLE orders;更新统计信息然后再次查看执行计划。是否使用了OR或!等导致索引失效的条件通过这一步你很可能已经能将问题范围从“SQL慢了”缩小到“因为某个原因索引没被用上”。3. 扩大搜索检查系统与环境的“不在场证明”如果SQL本身的执行计划看起来“合理”或者变更不足以解释5秒的差距那么就要怀疑是否是环境出了问题。你需要为其他可能性寻找“不在场证明”或确认其“犯罪事实”。3.1 资源争用与锁检查锁信息MySQL:SHOW ENGINE INNODB STATUS\G查看LATEST DETECTED DEADLOCK和TRANSACTIONS部分。更直接地查询information_schema.INNODB_LOCKS和INNODB_LOCK_WAITS表。如果发现你的慢查询正在等待某个锁Lock wait timeout那就要找到持有锁的会话和SQL。检查系统资源磁盘I/O使用iostat -x 1查看%util和await。如果磁盘利用率持续100%或等待时间很长说明磁盘是瓶颈。内存使用free -h或vmstat 1。观察是否发生了大量交换si/so交换会导致性能急剧下降。网络虽然不常见但网络抖动也可能影响分布式数据库或应用连接。3.2 外部变更与配置这是“昨天好今天坏”问题的关键排查方向。你需要像一个变更管理员一样提问数据库是否有变更是否进行了版本升级/小版本更新是否调整了关键参数如innodb_buffer_pool_size缓冲池、query_cache_*查询缓存MySQL 8.0已移除、optimizer_switch优化器开关等。对比昨天和今天的参数文件。应用是否有变更是否发布了新版本新代码是否传入了不同的查询参数例如昨天查user_id123今天查user_idNULL。连接池配置是否被修改是否有连接泄漏导致并发量激增数据是否有变更除了数据量数据结构是否变化增加了新字段字段类型改变是否运行了大的UPDATE/DELETE语句产生了大量碎片或死元组对于PostgreSQL需要VACUUM硬件/底层是否有变更云数据库实例是否被迁移或底层硬件降配是否从本地SSD盘被迁移到了网络存储4. 构建你的长效防御体系从救火到防火一次成功的故障排查价值不仅在于解决了当下问题更在于如何避免重蹈覆辙。你需要把这次紧急排查的经验沉淀为团队可复用的监控和防御流程。4.1 建立监控与告警基线不能等CPU到90%才行动。应该建立更前置的指标监控慢查询监控启用并定期分析慢查询日志slow_query_log。设置合理的long_query_time如1秒。使用工具如pt-query-digest对慢SQL进行聚合分析找到最耗资源的查询模式。性能指标监控QPS/TPS每秒查询/事务数突增可能预示问题。连接数监控活跃连接数和最大连接数使用率。缓冲池命中率对于InnoDB缓冲池命中率应接近100%。低于95%可能意味着内存不足或扫描了太多数据。锁等待监控平均锁等待时间。设置智能告警不要只对CPU使用率告警。对“慢查询数量突增”、“连接数暴增”、“缓冲池命中率下降”等指标设置告警能在问题影响用户体验前提前发现。4.2 制定标准排查清单Runbook将本次的排查步骤固化下来形成团队的“数据库性能问题标准排查清单”1. 症状确认 - [ ] 确认CPU高消耗进程是否为数据库。 - [ ] 使用 SHOW PROCESSLIST 定位可疑会话记录SQL。 2. SQL分析 - [ ] 获取当前慢SQL的 EXPLAIN 执行计划。 - [ ] 对比历史正常执行计划从监控平台或备份计划获取。 - [ ] 检查索引是否存在、是否被使用、数据分布是否变化。 3. 环境检查 - [ ] 检查锁信息 (SHOW ENGINE INNODB STATUS, 锁表查询)。 - [ ] 检查系统资源 (iostat, vmstat, top)。 - [ ] 回顾最近变更 (数据库配置、应用发布、数据迁移)。 4. 应急与根治 - [ ] 紧急情况考虑终止问题会话先记录。 - [ ] 根本解决根据分析结果选择优化SQL、调整索引、更新统计信息、修改配置或扩容资源。 - [ ] 事后将案例录入知识库优化监控告警规则。4.3 推行预防性实践SQL审核在上线前对所有新增或变更的SQL进行执行计划审核避免携带性能问题的代码进入生产环境。定期健康检查每周或每月例行检查数据库的索引有效性、统计信息准确性、表碎片情况。容量规划与压测对核心业务SQL进行压力测试了解其性能边界提前规划扩容。回到开头的场景那条从50毫秒“变质”到5秒的SQL就像一面镜子照出的往往不是单一的技术漏洞而是从开发习惯到运维体系的一系列缝隙。真正的资深不是背熟了所有的命令而是在警报响起的那一瞬间脑子里能立刻浮现出一张清晰的排查地图知道第一步该看哪里每一个异常信号可能指向何种根源以及如何在解决问题的同时把这次教训变成团队未来的一道防火墙。这个过程远比单纯给出一个“优化索引”的答案要复杂和深刻得多。 30款热门AI模型一站整合DeepSeek/GLM/Qwen 随心用限时 5 折。 点击领海量免费额度