在日常运维工作中,数据库服务器CPU使用率突然飙升至100%是较为常见的故障现象。该问题通常在业务高峰期、压测期间或定时任务执行时段突现,直观表现为应用响应变慢、SQL执行超时、数据库连接堆积等,严重时可导致业务中断。
业务量突增与并发风暴:短时间内高并发等场景带来瞬时QPS飙升,如很多人同时点击同一个功能,大量会话击穿应用打到数据库层,或应用端故障导致重试风暴,超出数据库承载水位。
锁等待与阻塞堆积:长事务未提交或加锁顺序不一致,引发大面积锁等待,会话堆积后CPU资源被连接管理和锁调度耗尽。
慢SQL与执行计划劣化:表中未添加合理索引或SQL未走索引或统计信息过期,导致优化器选择低效执行计划,大量消耗CPU资源进行全表扫描、大量回表操作产生逻辑读、排序或哈希连接。
执行top -c ,输入P 可按照CPU占用率进行排序。使用top命令查看系统整体CPU使用率,重点关注us(用户态)和sy(内核态)的占比,如果us(用户态)占比高且则查dmserver进程占用高,则基本锁定是数据库问题,否则非数据库问题。
执行free -g查看是否使用到swap,内存不足也可能导致CPU使用率抖动。
执行iostat -x 1 ,查看是否存在持续的%util>90%或w_await >20ms的情况。 CPU使用率升高可能由于I/O瓶颈拖累CPU。
查看活动回话数是否远高于平常,是否有大量会话堆积,或者已知的业务激增情况,也可以根据同一时间段内CPU占用异常和正常时生成的sql日志情况进行推断,例如CPU占用异常时sql日志生成更频繁。如相差不是特别明显,则继续向慢SQL方向排查。
select * from v$sessions where state='ACTIVE';
SELECT *
FROM (
SELECT sess_id,
sql_text,
datediff (ss, last_recv_time, SYSDATE) Y_EXETIME ,
SF_GET_SESSION_SQL (SESS_ID) fullsql ,
clnt_ip
FROM
V$SESSIONS
WHERE
STATE = 'ACTIVE'
)
WHERE
Y_EXETIME >= 2; --执行时间超 2s,可以自定义该时间
通过V$SQL_STAT和V$SQL_STAT_HISTORY系统视图查看语句的资源开销(ENABLE_MONITOR=1 才 开 始 监 控),其中V$SQL_STAT记录当前正在执行的SQL语句的资源开销,V$SQL_STAT_HISTORY记录历史SQL语句的资源开销,单机最大行数为 10000。视图官方文档。(打开网页直接搜 SQL_STAT)
select SESSID,
LOGIC_READ_CNT,
SQL_TXT
from V$SQL_STAT
order by LOGIC_READ_CNT DESC;
select SESSID,
LOGIC_READ_CNT,
SQL_TXT
from V$SQL_STAT_HISTORY
order by LOGIC_READ_CNT DESC;
通过以上查询,可以找到逻辑读次数最多的历史SQL和当前SQL。根据查询出来的SQL,可以查看其执行计划信息
关注执行计划中是否出现BLKUP2操作符
BLKUP2表示通过二级索引回表获取数据,若该操作符对应的ROWS估算值较大(如超过10万行),说明存在大量回表操作。每次回表都是一次独立的逻辑读,大量回表会直接推高CPU的us消耗。
若无BLKUP2回表操作,则需关注是否因缺少正确索引而进行了CSCN2全表扫描
全表扫描本身并不一定会导致性能问题,但其对缓存池的副作用值得特别关注:数据库执行全表扫描时会先从缓存中寻找数据页,对于未缓存的数据页会触发中断处理,从硬盘拷贝数据到缓存中。这个过程不仅消耗sy(内核态CPU),还会将其他SQL频繁访问的热点数据挤出缓存池。当这些被挤出的热点SQL再次执行时,又需要重新从硬盘读取数据,进一步增加I/O消耗和sy%占用率,形成恶性循环。
可通过 top -p v$sessions视图中查询对应的线程会话,验证对应的sql是否执行异常。
通过此时的线程号在数据库中的v$sessions视图中查询对应的线程会话,验证对应的sql是否执行异常
SELECT * FROM V$SESSIONS WHERE THRD_ID = <pid>;
可通过分析sql日志文件对整体慢sql情况进行分析。
检查数据库的sqllog功能是否开启,PARA_VALUE =1为已开启
select PARA_NAME,PARA_VALUE from v$dm_ini where para_name='SVR_LOG';
如未开启,可以先配置实例目录下的sqllog.ini文件配置文件生成路径和文件大小、数量的信息,再开启sqllog功能,如不修改配置文件则默认生成在软件安装目录的log文件夹下,保留数量为5个,每个128M,文件命名格式为dmsql_DMSERVER_20260624_004004.log
SP_SET_PARA_VALUE(1,'SVR_LOG',1);
收集cpu占用高时段的sqllog文件,使用sqllog分析工具进行分析。
如获取到大量的update,delete语句时,且执行时间与平时时间段差距非常大。需考虑数据库是否存在阻塞,若数据库发生阻塞,则会产生大量的会话堆积,占用SESSION,导致应用系统无响应、报错数据库达到最大会话数限制等。查询数据库是否存在阻塞,与获取到的异常SQL进行对比。
--使用该sql查询是否存在阻塞,如有结果集则存在阻塞
SELECT DS.SESS_ID "被阻塞的会话ID",
DS.SQL_TEXT "被阻塞的SQL",
DS.TRX_ID "被阻塞的事务ID", (
CASE L.LTYPE
WHEN 'OBJECT'
THEN '对象锁'
WHEN 'TID'
THEN '事务锁'
END
CASE ) "被阻塞的锁类型",
DS.CREATE_TIME "开始阻塞时间",
SS.SESS_ID "占用锁的会话ID",
SS.SQL_TEXT "占用锁的SQL",
SS.CLNT_IP "占用锁的IP",
L.TID "占用锁的事务ID"
FROM V$LOCK L
LEFT JOIN V$SESSIONS DS
ON DS.TRX_ID = L.TRX_ID
LEFT JOIN V$SESSIONS SS
ON SS.TRX_ID = L.TID
WHERE L.BLOCKED = 1;
--如存在阻塞,根据查询到的"占用锁会话ID"进行关闭会话
SP_CANCEL_SESSION_OPERATION(SESS_ID);
SP_CLOSE_SESSION(SESS_ID);
如获取到的某一类简单的 SQL 语句在并发场景下执行速度显著下降,此时需要分析此条 SQL 的执行计划,一般是由于此 SQL 回表太多引起的,当高并发上来时,回表会消耗主机大量资源(sys),引起 SQL 执行缓慢,造成系统瓶颈,情况复杂时会导致系统处于瘫痪状态,占用别的 SQL 系统资源,导致其他SQL执行缓慢。
出现此问题则需要消除 SQL 中的回表操作符,常用的方法有:创建适当的索引(包括组合索引),select 查询选出的结果集中不要出现无关的字段,尽量使用索引中的字段,减少执行计划中的回表操作符。或在对应的表上创建适当的聚集索引或者组合索引,减少执行计划中的回表操作符。
必须先与用户或相关负责人确认是否可以kill会话,并告知风险
定位到异常会话的sess_id后在数据库里面执行 SQL 语句
sp_close_session(sess_id);
这种一般都是大量的几乎相同的sql占满会话资源,使用下面的方法先查询一下再执行关闭会话的操作
BEGIN
FOR V_SESSID IN (SELECT SESS_ID FROM V$SESSIONS where CLINT_IP !=:1 and 条件)
LOOP
SP_CLOSE_SESSION(V_SESSID.SESS_ID);
END LOOP;
END;
建议使用数据的定时作业的方式进行监控
SELECT *
FROM ( SELECT sess_id,
sql_text,
datediff (ss, last_recv_time, SYSDATE) Y_EXETIME,
SF_GET_SESSION_SQL (SESS_ID) fullsql,
clnt_ip
FROM V$SESSIONS
WHERE STATE = 'ACTIVE' )
WHERE Y_EXETIME >= 2;
SELECT sess_id "会话号",
SF_GET_SESSION_SQL (SESS_ID) "会话执行完整SQL",
datediff (ss, last_recv_time, SYSDATE) EXEC_TIME, --执行时间
user_name,
TRX_ID,
CREATE_TIME,
LAST_RECV_TIME,
LAST_SEND_TIME,
clnt_ip "会话发起IP"
FROM V$SESSIONS
WHERE STATE = 'ACTIVE';
文章
阅读量
获赞
