Oracle数据库的会话数直接反映应用连接规模和系统负载。一个看似正常的实例,可能因为连接泄漏或长事务堆积,导致总会话数逼近processes参数上限,而活跃会话数突然飙升后,CPU与I/O资源被快速耗尽。监控会话数不能只记录一个总量,必须区分空闲连接、活跃会话以及阻塞会话,并关联等待事件和SQL执行情况,才能快速定位是连接配置问题还是SQL性能问题。

下文从视图字段、监控SQL、参数阈值和自动化采集四个方面展开,给出可直接使用的查询和分析方法。
一、先分清:总会话、活跃会话与阻塞会话
Oracle中每个客户端连接通常会创建一个会话,但连接与会话并不完全一一对应。在共享服务器模式下,一个连接可能对应多个会话,而专用服务器模式下二者基本等同。从监控角度看,V$SESSION视图记录当前所有会话,其中STATUS字段标识会话是否正在执行SQL。ACTIVE表示当前正在调用或等待某个数据库操作,INACTIVE表示会话空闲,KILLED表示正在被标记删除。
为什么会话数很多但数据库并不慢?因为大量INACTIVE会话只是占着连接槽位,不分配CPU时间。真正需要重点关注的是ACTIVE会话,它们可能正在执行SQL、等待锁、等待I/O或消耗CPU。活跃会话数量长期大于CPU核数,说明系统存在排队;如果伴随大量enq: TX等待,则要检查锁竞争。V$SESSION里的LAST_CALL_ET表示自上一次调用以来的秒数,可以辅助判断空闲时长。
下面这条SQL可以快速查看当前总会话数、活跃会话数以及按状态分组的情况。
SELECT status,
COUNT(*) AS session_count
FROM v$session
WHERE type = 'USER'
GROUP BY status
ORDER BY session_count DESC;
这里只统计用户会话,排除了Oracle自身后台进程。若还需要区分服务名或模块,可以加上service_name和module字段进行二次聚合。
二、核心监控视图与实用SQL
会话监控主要依赖V$SESSION、V$PROCESS和V$RESOURCE_LIMIT三张视图。V$SESSION提供会话级别的状态、登录时间、用户名、机器名、程序名、SQL_ID、等待事件等;V$PROCESS对应操作系统进程信息,能帮助定位某个PID占用CPU过高时的会话;V$RESOURCE_LIMIT则显示processes、sessions等资源当前用量与最大限制。
查看数据库允许的最大会话数与当前使用情况,是判断是否接近上限的基础操作。当current_utilization接近limit_value时,新连接可能报ORA-00018或ORA-00020错误。
SELECT resource_name,
current_utilization,
max_utilization,
limit_value
FROM v$resource_limit
WHERE resource_name IN ('processes', 'sessions');
如果想找出哪些客户端占用了最多连接,可以按机器名和程序聚合。连接风暴通常来自某一台应用服务器或某个中间件池配置错误。
SELECT machine,
program,
COUNT(*) AS conn_count
FROM v$session
WHERE type = 'USER'
GROUP BY machine, program
ORDER BY conn_count DESC;
活跃会话排查时,需要观察等待事件。V$SESSION中的event字段表示会话当前正在等待的事件。若某个SQL_ID长时间处于ACTIVE状态,再关联V$SQLAREA可以找出具体SQL文本。下面SQL查找持续活跃超过60秒的会话,并显示等待事件和最近执行SQL。
SELECT s.sid,
s.serial#,
s.username,
s.machine,
s.event,
s.last_call_et,
s.sql_id,
SUBSTR(q.sql_text, 1, 120) AS sql_text
FROM v$session s
LEFT JOIN v$sqlarea q
ON s.sql_id = q.sql_id
WHERE s.type = 'USER'
AND s.status = 'ACTIVE'
AND s.last_call_et > 60
ORDER BY s.last_call_et DESC;
上述SQL中的>在代码块中已做转义,复制到客户端后仍然是大于号,语法保持正确。对于诊断历史问题,V$ACTIVE_SESSION_HISTORY按秒采样保存活跃会话快照,可以查看过去一段时间内的会话活动趋势,而不需要一直开启实时抓取。
三、会话数异常的常见原因与处理
会话总数突然升高通常有四个原因:应用连接池上限设置过大、代码忘记关闭连接、中间件连接复用失效、以及数据库processes参数过小。前三种都属于应用侧问题,最后一种属于参数配置问题。处理时先确认哪个来源增长最快,再决定调整哪一端。
如果会话数已经达到sessions或processes上限,新连接会失败。此时普通用户可能无法登录,需要以sysdba身份登录执行查询和清理。可以通过下面SQL找到空闲时间很长的INACTIVE会话,它们通常是泄漏连接,可以安全清理。
SELECT sid,
serial#,
username,
machine,
program,
last_call_et,
status
FROM v$session
WHERE type = 'USER'
AND status = 'INACTIVE'
AND last_call_et > 3600
ORDER BY last_call_et DESC;
清理会话使用ALTER SYSTEM KILL SESSION语句,并带上sid和serial#。如果会话正在回滚,可以加IMMEDIATE选项。但KILL并不总是立刻释放资源,需要等待回滚或使用DISCONNECT SESSION POST_TRANSACTION等更精细的操作。
ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE;
调整参数时,sessions由processes派生,通常sessions约等于processes的1.1倍加5,但不同版本略有差异。修改processes需要重启实例,生产环境需提前规划。可以通过ALTER SYSTEM SET processes=500 SCOPE=SPFILE;然后重启。若只是临时应急,可以先在连接池侧降低最大连接数,再分批清理空闲会话,避免重启。
四、建立可持续的会话监控与告警
单次查询只能解决突发问题,长期稳定运行需要定时采集和趋势分析。最简单的方案是将核心指标写入监控表,每5分钟执行一次,保留30天。这样当会话数异常时,可以对比历史同时段基线,判断是周期性波动还是突发异常。
下面是一个采集脚本示例,统计总用户会话、活跃会话、空闲会话以及当前processes使用率,并插入监控表。
CREATE TABLE monitor_session_hist (
sample_time DATE,
total_sessions NUMBER,
active_sessions NUMBER,
inactive_sessions NUMBER,
processes_used NUMBER,
processes_limit NUMBER
);
INSERT INTO monitor_session_hist
SELECT SYSDATE,
COUNT(*),
SUM(CASE WHEN status = 'ACTIVE' THEN 1 ELSE 0 END),
SUM(CASE WHEN status = 'INACTIVE' THEN 1 ELSE 0 END),
(SELECT current_utilization FROM v$resource_limit WHERE resource_name = 'processes'),
(SELECT limit_value FROM v$resource_limit WHERE resource_name = 'processes')
FROM v$session
WHERE type = 'USER';
COMMIT;
如果使用Oracle Enterprise Manager,可以直接查看实时会话图、Top SQL和告警历史。没有OEM的环境可以使用开源监控工具,例如配合Prometheus的oracledb_exporter采集V$SESSION和V$PROCESS指标,再用Grafana配置告警规则。关键告警项可以设为:活跃会话数超过CPU核数的2倍持续5分钟、总会话数超过limit_value的90%、单台机器连接数增长超过阈值。
最后,监控不能只看数据库内部,还要与应用连接池指标交叉验证。很多连接池会暴露活跃连接、空闲连接、等待获取连接的线程数。将数据库侧活跃会话与应用连接池等待数叠加起来,才能判断连接不足究竟发生在数据库层还是应用排队层。数据库会话监控的目的是提前发现风险,而不是等ORA告警后才被动响应。建立基线、保留历史、设置分层告警,这套思路对任何版本的Oracle都适用。