注册
性能故障分析
专栏/技术分享/ 文章详情 /

性能故障分析

诗想与论语 2026/09/04 85 0 0
摘要

1问题描述

业务系统出现明显的性能退化,用户端反馈订单查询接口响应时间从毫秒级急剧上升至数秒甚至超时。监控平台显示,数据库服务器CPU使用率持续处于95%以上,系统负载(load average)远超物理核心数,业务高峰期出现大量请求堆积,部分请求因超时而失败。初步排查排除了网络和存储硬件故障,怀疑是数据库内部执行效率问题导致资源耗尽。为定位根本原因并快速恢复服务,需对数据库运行状态进行系统性分析。

2检查系统资源

vmstat查看系统资源情况:
image.png
分析可知,运行队列的数量很大,远超CPU内核数量,说明有大量进程在排队等待CPU,而其余的系统资源,内存与磁盘等并不是瓶颈所在,相关分析如下表:

指标 数值 含义
r(运行队列) 59 ~ 136 远高于CPU核数,有大量进程在排队等待CPU
us(用户态CPU) 94% ~ 97% CPU绝大部分时间在运行用户进程,接近满载
sy(内核态CPU) 3% ~ 6% 系统内核开销正常
id(空闲CPU) 0% CPU已完全被榨干,没有任何空闲
si/so(Swap换入换出) 0 未发生内存与磁盘的频繁交换,内存暂不是瓶颈
bi/bo(磁盘读写) 低 磁盘I/O正常,不是瓶颈

然后使用top命令查看,验证CPU是否真的被占满
image.png
此处证明,CPU确实已经快被占满,成为主要的问题所在

3查看具体进程

通过TOP命令查看到的,是dmserver这个进程导致的CPU爆满,那么我们就确定了大致方向

4查看达梦内部原因

4.1查询会话数量

执行以下命令查询会话数量:
SELECT STATE, COUNT(*) AS 会话数量
FROM V$SESSIONS
GROUP BY STATE;

image.png
我们可以发现,有大量会话在执行SQL,说明并发量很高,会话数量堆积了很多,那么就需要考虑会话堆积的原因:
是存在锁还是因为SQL执行太慢

4.2查询是否存在锁等待

执行语句,排查是否存在会话在等待锁:
SELECT COUNT(*) AS 当前锁等待会话数
FROM V$TRXWAIT;

image.png
图中结果说明并不存在锁等待会话,那我们排除了这一原因。

4.3查询慢SQL

排除了锁的原因之后,就要考虑是慢SQL的问题:
查看当前当前是否存在慢SQL:
SELECT
SESS_ID,datediff(ss, LAST_RECV_TIME, SYSDATE) AS 已执行秒数,
SUBSTR(SQL_TEXT, 1, 200) AS SQL内容
FROM V$SESSIONS
WHERE STATE = ‘ACTIVE’
AND SQL_TEXT IS NOT NULL
AND datediff(ss, LAST_RECV_TIME, SYSDATE) > 5
ORDER BY 已执行秒数 DESC;
image.png
通过查询,可以看到当前存在大量的慢SQL正在执行高达167条,并且都指向同一条SQL语句,说明是这一条SQL语句被大量的执行导致的。

4.4分析慢SQL语句

我们通过AUTOTRACE查看一下这条语句的执行计划:
SET AUTOTRACE TRACE
SELECT * FROM (SELECT inner_query.*, ROWNUM rnum FROM (SELECT o_id, o_totalprice FROM SYSDBA.orders_tp WHERE o_custkey = ? ORDER BY o_id DESC) inner_query WHERE ROWNUM <= 5) WHERE rnum > 0
image.png
分析它的执行计划:
#SSEK2: scan_range(min,max) – 全索引范围扫描,不精准
#BLKUP2: [1, 300->40200, 102] – 回表 40,200 次
#SLCT2: [1, 300->5, 102] – 过滤后只命中 5 行

我们查看一下当前索引:
SELECT
INDEX_NAME, – 索引名称
COLUMN_NAME, – 列名
COLUMN_POSITION, – 列在索引中的位置(1表示第一列)
DESCEND – 排序方向(ASC升序 / DESC降序)
FROM USER_IND_COLUMNS
WHERE
TABLE_NAME = ‘ORDERS_TP’ – 表名,注意要大写
ORDER BY
INDEX_NAME, COLUMN_POSITION;
image.png
走的索引是 INDEX33555740这条索引,优化器为了满足 ORDER BY o_id DESC 选择走 O_ID 索引,这样可以省去排序,但 O_ID 索引无法精准过滤 o_custkey,只能全扫后再过滤。全扫的回表动作是随机I/O,极其昂贵,加上250并发,直接打满CPU,那么我们可以锁定原因:当前索引 (O_ID) 的列顺序与查询条件不匹配。

4.5查看数据分布

接下来,我们要查看一下数据的分布情况,来确保旧的索引确实存在不合理之处,并且根据数据分布来建立新的索引。

4.5.1验证查询条件实际匹配的数据量

执行以下SQL语句:
SELECT COUNT(*) FROM orders_tp WHERE o_custkey = 1;
image.png
这说明查询的数据在表中只有10行,但是确扫描了4万多行,说明走错了索引,做了大量无效扫描

4.5.2查询字段的全局数据分布

执行以下命令,查看
SELECT o_custkey, COUNT() FROM orders_tp GROUP BY o_custkey ORDER BY COUNT() DESC LIMIT 10;
image.png
该字段的数据分布极度均匀——每个不同值仅对应 10 行数据,表中共有 10 万行记录,意味着 o_custkey 拥有约 1 万个不同值,选择性极高。在数据库中,选择性越高的字段,越适合作为复合索引的前导列,因为它能最快地将结果集从 10 万行缩小至个位数,最大化索引的过滤效果。

4.5.3查询表的总数据量和O_ID的范围
执行以下SQL语句,评估走错索引带来的放大效应
SELECT MIN(o_id), MAX(o_id), COUNT(*) FROM orders_tp;
image.png
image.png
表里有10万数据,O_ID从1到10万连续分布,执行计划显示扫描了4万行,也就是说,实际需要的数据只有10行,确扫描了4万多行,放大倍数为4020倍。
综合数据分布来看,当前索引是存在不合理之处的,因此我们需要新建一个同时包含过滤字段和排序字段的复合索引。

5解决问题

5.1新建索引

在确定了问题的原因是索引的不合理,以及分析了当前的数据分布之后,我们可以根据需要来建立新的索引,分析这条慢SQL语句,它的核心逻辑是WHERE o_custkey = ?和ORDER BY o_id DESC,那么核心需求就是精准过滤和有序输出,所以我们复合索引的列顺序应该为:(o_custkey, o_id DESC)
因此,我们建立索引:
CREATE INDEX IDX_ORDERS_CUSTKEY_OID_DESC
ON SYSDBA.orders_tp (o_custkey, o_id DESC);

5.2查看效果

最明显的效果就是我们的CPU占用率成功降低:
image.png
会话堆积也不复存在:
image.png

5.3查看新的执行计划

SET AUTOTRACE TRACE
SELECT * FROM (SELECT inner_query.*, ROWNUM rnum FROM (SELECT o_id, o_totalprice FROM SYSDBA.orders_tp WHERE o_custkey = ? ORDER BY o_id DESC) inner_query WHERE ROWNUM <= 5) WHERE rnum > 0;
image.png
优化后,我们分析新的执行计划:
scan_range[(exp_param,min), (exp_param,max)] 直接定位到 o_custkey = ? 的索引页,只扫描该客户的数据,而不是全表。回表次数也只是回表了10次,回表数量大大降低。逻辑读数据也下降到43次,证明我们添加的索引正确且高效。

6.总结

本次性能故障的排查与解决,完整展示了从系统现象到数据库内核、从问题定位到索引优化的标准化处理流程。
排查从 vmstat 和 top 命令入手,精准定位 CPU 资源耗尽且瓶颈落在 dmserver 进程;随后深入达梦数据库内部,通过 VSESSIONS 发现大量活跃会话堆积,并利用 VTRXWAIT 排除了锁等待的干扰,将方向锁定在慢 SQL 上。
借助 V$SESSIONS 实时监控,快速抓取到大量并发执行的同一条 SQL,并通过 AUTOTRACE 获取其执行计划,发现了 scan_range(min,max) 全索引扫描、回表 40,200 次却仅命中 5 行的严重性能问题。
通过对 USER_IND_COLUMNS 的索引分析和三组数据分布查询的论证,确认了现有单列索引 (O_ID) 与查询条件不匹配的根本原因,并基于“高选择性字段作为前导列”的原则设计了复合索引 (O_CUSTKEY, O_ID DESC)。
优化后执行计划的 scan_range 从全表范围缩小为精准定位,回表次数降至 10 次,逻辑读从 121,055 降至 43 次,CPU 占用率从 95% 降至 5% 以下,会话堆积消除,故障模拟程序评分达到 100 分。
整个排查过程逻辑严密、层层递进,充分体现了“现象 → 定位 → 分析 → 验证 → 解决”的闭环思路。

评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服