SMON不释放临时段是因未触发或被阻塞,应优先查清卡住原因并手动清理:通过v$sort_usage定位僵尸段,用DROP_SEGMENTS事件或修改DEFAULT STORAGE参数强制SMON扫描释放。

SMON 不释放临时段不是进程故障,而是它根本没被触发或被阻塞了——直接杀会话、调参数、发事件比等它自动清理更可靠。
查清楚谁卡住了临时段
先确认是不是真有未释放的活跃排序段,而不是监控误报。运行以下查询:
SELECT se.username, se.sid, se.serial#, se.sql_id, su.tablespace, su.segtype, su.blocks * 8 / 1024 AS mb_used FROM v$session se, v$sort_usage su WHERE se.saddr = su.session_addr AND su.segtype = 'SORT';
重点看 blocks 值是否持续不降、sql_id 是否指向一个长期运行(或已断开但未清理)的语句。如果 sid 对应会话状态是 INACTIVE 但仍在 v$sort_usage 里,基本就是“僵尸临时段”。
- 常见诱因:BI 工具执行含
WITH子句的大查询后客户端异常中断 - 注意:
v$lock中若存在type = 'TS'的锁,说明临时段被锁住,得先alter system kill session 'sid,serial#'再处理 - RAC 环境下要查所有实例的
v$sort_usage,别只看本节点
用事件强制 SMON 清理临时段
Oracle 19c 中 SMON 默认每 2 小时 5 分钟才扫一次临时段,且每次最多清 5 个,完全跟不上高频排序负载。最直接的办法是手动触发清理:
SELECT ts#, name FROM ts$ WHERE name = 'TEMP'; -- 假设返回 ts# = 3,则执行: ALTER SESSION SET EVENTS 'immediate trace name DROP_SEGMENTS level 4';
注意:level 值必须是 ts# + 1,不是表空间名。这个事件会通知 SMON 立即扫描并释放该表空间中所有非活动临时段。
- 如果执行后
v$sort_usage仍不为空,检查是否有TS锁未清除,或该临时表空间是否被设为只读 - 该事件不会影响正在使用的段,只清理“已结束但未标记为 free”的段
- 在 RAC 中需在每个实例上单独执行
改 storage 参数骗 SMON 主动干活
这是 Metalink 推荐的老办法,在 19c 依然有效。原理是修改临时表空间的默认存储参数,让 SMON 认为“配置变了”,从而触发一次主动扫描:
ALTER TABLESPACE TEMP DEFAULT STORAGE (pctincrease 0); -- 等 30 秒左右,再查 v$sort_segment 确认 used_blocks 是否下降 ALTER TABLESPACE TEMP DEFAULT STORAGE (pctincrease 10);
pctincrease 0 是个“无效值”,SMON 在下次巡检时发现不合法配置,就会顺手把积压的临时段全清掉。
- 别用
minextents或maxextents改,19c 中这些参数已被废弃,改了也无效 - 操作前确保你有
ALTER TABLESPACE权限,且不是在 PDB 中对 CDB$ROOT 的 TEMP 表空间操作 - 如果表空间是本地管理(LMT),这个方法比事件法更稳定;如果是字典管理(DMT),优先用事件法
别忽略 PGA 和 SQL 本身的优化
临时段爆满常是结果,不是原因。19c 中若 pga_aggregate_target 设置过小(比如 TEMP,即使 SMON 清得再勤也赶不上生成速度。
运行以下语句看排序内存占比:
SELECT name, value/1024/1024 AS mb FROM v$pgastat
WHERE name IN ('total PGA allocated', 'total PGA used for auto workareas');如果 “used for auto workareas” 占比长期 > 80%,说明 PGA 不足或 SQL 没走内存排序。
- 临时方案:对关键 SQL 加 hint
/*+ USE_HASH_AGGREGATION */或调大sort_area_size(仅 session 级) - 根本方案:检查执行计划里有没有
TEMP TABLE TRANSFORMATION或多层WITH,这类结构极易撑爆 TEMP -
ALTER SYSTEM SET pga_aggregate_target=4G SCOPE=BOTH;后记得观察v$pgastat变化,别盲目拉太高导致 OOM
真正难处理的不是怎么清,而是清完几分钟又涨回去——那说明背后有 SQL 在反复申请、却不正常释放。盯住 v$sort_usage 和 v$sql 的关联输出,比反复调 DROP_SEGMENTS 有用得多。


















