喜欢把枯燥的技术文档变成"手把手教程",不讲空话,只讲怎么连、怎么写、怎么优化。
数据库监控现在做得越来越完善了。CPU 升高、I/O 波动、会话堆积、慢 SQL------这些异常基本都能被快速发现。
但发现问题只是第一步。真正的挑战在于:知道了数据库慢之后,怎么找到根因?
一次性能问题,可能同时涉及服务器资源、SQL 执行效率、锁等待、长事务、索引缺失等多个因素。传统排查方式是在不同页面之间反复切换------先看监控面板确认异常时间点,再去查慢 SQL 日志,再去查锁等待信息,再去查执行计划------靠 DBA 的经验把这些碎片拼成完整的问题链。
这个拼接过程,就是排障最耗时的地方。
今天把一套完整的数据库诊断链路拆开讲清楚。从异常时间点开始,顺着线索一步步追到根因。不管你是用金仓的 KEMCC、PostgreSQL 的 pg_stat 系列视图、还是 MySQL 的 performance_schema,这套诊断思路是通用的。
第一步:从一个异常时间点开始
数据库响应变慢,第一件事是确认"什么时候开始慢的"。
常规做法是看监控面板上的几条核心曲线:CPU 使用率、磁盘 I/O、TPS/QPS、活跃会话数。
但这些指标只能告诉你"慢了",不能告诉你"为什么慢"。
关键一步:把服务器资源和数据库指标放在同一张时间轴上。这样当某个时段出现性能异常时,你能立刻看到同时刻数据库在做什么------是突然冒出了一批慢 SQL?还是某个长事务在持锁?还是连接数暴涨?

单条性能曲线的价值有限,性能曲线 + 同时刻的数据库活动,才有诊断价值。
第二步:锁住了?看"谁在等谁"
确认了异常时间点和关联的 SQL 之后,下一步是判断:这条 SQL 慢,是因为自身效率低,还是因为被其他事务阻塞了?
这是排查中最容易搞混的一个点。
一条 SQL 自身执行可能只需要 100ms,但如果它要访问的表被另一个长事务锁住了,它就得等着。等 10 分钟------从外面看,这条 SQL "跑了 10 分钟"。但这不是它慢,是它在等。

怎么区分? 看锁等待信息:
- 等锁列表:当前正在等待锁的会话、等的是哪把锁、等了多久
- 持锁列表:当前持有锁的会话、持的是什么锁、持了多久
- 等锁流程图:谁持锁、谁等锁、等待时间多长------一张图还原会话间的阻塞关系

有了这个信息,你就能判断:
- SQL 慢 + 没有锁等待 → SQL 自身效率低,看执行计划
- SQL 慢 + 有锁等待 → 被其他事务阻塞,查长事务
第三步:根因分析------把所有线索串起来
实际生产中的性能问题,往往不是单一因素,是多因素叠加:
- 一个长事务在后台持锁
- 一条业务 SQL 要访问同一张表,被阻塞
- 这条 SQL 自身的执行效率也不高(缺索引)
- 持锁时间被拉长,更多会话开始排队
- 最终表现:业务响应越来越慢
单独看每一项,都是"局部异常"------长事务是问题、慢 SQL 也是问题、缺索引也是问题。但只有判断出因果关系,才能锁定真正的根因。
完整的诊断链路应该是:
发现异常(指标波动)→ 锁定问题 SQL → 分析等待关系(是否被阻塞)→ 判断问题来源(自身效率 vs 外部阻塞)→ 定位根因(长事务 / 缺索引 / 资源瓶颈)→ 辅助优化

这个链路里,每一步的输出是下一步的输入。不需要在不同页面之间反复切换,线索是连续的。
第四步:如果是索引问题,怎么确认?
如果根因指向了 SQL 自身效率低(不是被阻塞),那大概率是索引问题。
三种情况:
缺失索引。 SQL 在走全表扫描,但某个字段上加索引能大幅减少扫描量。通过执行计划的 Seq Scan 和实际扫描行数对比,能快速判断。
无效索引。 索引建了,但优化器没用。原因可能是统计信息过时、索引选择率太低(比如一个只有 3 个值的字段建了索引)、或者 SQL 写法导致索引失效(比如 LIKE '%xxx')。
低效索引。 索引用了,但效果不好。比如复合索引的字段顺序不对,导致只命中了前导列。
怎么查? 看 SQL 的执行计划 + 索引使用情况统计。执行计划告诉你优化器选了什么路径,索引统计告诉你这个索引被用了多少次、命中率如何。两者对比,就能判断索引是"该建没建"、"建了没用"还是"用了但效果差"。
第五步:SQL 统计------看历史趋势,不只盯当下
排到根因之后,别急着下手优化。先看一眼这条 SQL 的历史执行情况。
有些 SQL 平时跑得好好的,今天突然慢了。这种情况大概率不是 SQL 本身的问题,是数据量增长导致执行计划变了,或者统计信息过时了。
有些 SQL 是一直慢,只是今天业务量上来了才被注意到。这种是"老病号",之前没人管而已。
看 SQL 统计能帮你区分这两种情况:
- 调用次数趋势:这条 SQL 最近是不是调用量突然变大了?
- 平均耗时趋势:是一直慢,还是最近才变慢?
- 历史执行计划变化:执行计划最近有没有改?如果有,是什么时候改的、改成了什么?
这些信息决定了你优化的方向------如果是执行计划变了,可能需要更新统计信息;如果是一直慢,需要加索引或改写 SQL;如果是调用量暴涨,可能需要从架构层面做缓存或拆分。
诊断链路全景图
把上面五步串起来,一个完整的性能排查链路是这样的:
sql
性能分析(异常时间点 + 关联SQL)
→ SQL 分析(锁定问题语句)
→ 锁分析(是否被阻塞?谁持锁?等多久?)
→ 根因分析(自身效率 vs 外部阻塞 → 长事务 / 缺索引 / 资源瓶颈)
→ 索引分析(缺失 / 无效 / 低效 → 确认执行计划)
→ SQL 统计(历史趋势 → 优化方向)
这套链路在金仓的 KEMCC 里是内置的------七类分析(性能、锁、根因、SQL、存储、索引、SQL 统计)协同工作,信息在统一诊断链路里连续下钻。你不需要在监控面板、慢查询日志、锁视图、执行计划工具之间反复切换,线索从异常时间点开始就串好了。
不管你用什么工具,诊断的核心不是"功能多",是"信息能关联起来" 。能从一个异常时间点出发,连续下追到根因,中间不丢线索,这就是好的诊断体系。
排查决策框架
对着你的现象,按这个框架走:
| 现象 | 下一步 | 可能原因 |
|---|---|---|
| CPU/IO 突然飙升 | 看同时刻在跑的 SQL | 大查询、批量操作、全表扫描 |
| 某条 SQL 突然变慢 | 看锁等待信息 | 被长事务阻塞 / 执行计划变了 |
| 多条 SQL 同时变慢 | 看锁等待链 + 资源指标 | 锁竞争 / 资源瓶颈 / 连接数打满 |
| SQL 一直慢 | 看执行计划 + 索引 | 缺索引 / 索引低效 / SQL 写法问题 |
| SQL 间歇性慢 | 看历史执行计划 + 统计信息 | 数据量增长导致计划漂移 / 统计信息过时 |
几个排查习惯
1. 先看锁,再看执行计划。 很多 DBA 看到慢 SQL 第一反应是看执行计划。但如果 SQL 慢是因为被锁了,执行计划是正常的------你得先确认它是不是在等。
2. 别只看当前,看趋势。 一条 SQL 现在的执行计划和昨天的可能不一样。统计信息过时、数据量增长都会导致执行计划漂移。历史趋势比单点数据有价值。
3. 长事务是隐形杀手。 一个长事务持锁,能让后面几十条 SQL 排队等。但长事务本身不一定"慢"------它可能在等用户操作,或者在跑一个正常的批处理。锁分析的价值就是把"慢 SQL"和"持锁事务"的因果关系连起来。
4. 根因不等于"第一个发现的问题"。 看到缺索引就加索引,看到长事务就杀事务------这是治标。真正的根因是:为什么这条 SQL 缺索引一直没发现?为什么这个长事务能跑这么久?把这两个问题解决了,下次类似问题就不会再出现。
总结
数据库排障最大的时间消耗不在"查",在"拼"------在不同页面之间切换,把碎片信息拼成完整的问题链。
好的诊断体系做的事,是把"拼"这个动作省掉。从异常时间点开始,性能分析定位时空、SQL 分析锁定语句、锁分析还原等待关系、根因分析关联因果、索引和 SQL 统计提供优化依据。线索连续下追,不用反复切换。
排障的终点不是"找到一条慢 SQL",是"搞清楚它为什么慢、下次怎么不让它慢"。
少一些反复排查,多一些有依据的判断。
后续我会继续分享数据库版本升级实战、云数据库 vs 自建这些话题,跟着我一篇篇学,数据库这块就没问题了。
有问题评论区见。
喜欢把枯燥的技术文档变成"手把手教程"。关注我,数据库这块我们一起搞定。