<p>enq: TX - allocate ITL entry等待事件源于事务长时间持有ITL槽不提交,导致其他会话因无法分配ITL槽而阻塞;根因为DELETE语句并发循环执行且未及时提交,使UPDATE语句被迫等待。</p>

查 v$active_session_history 里是否真有 LOB 相关等待
临时 LOB(如 DBMS_LOB.CREATETEMPORARY 创建的)不走常规 PGA 分配路径,也不会触发 in_hard_parse 或 direct path write temp;它的真实压力反映在 enq: TX - row lock contention、latch: lob allocation latch 或长时间的 PGA memory operation 等待上。别一上来就查 pga_allocated——临时 LOB 的内存可能已脱离会话上下文,但仍在 SGA 中未释放。
- 执行时加
WHERE sample_time > SYSDATE - 1/144(最近 10 分钟),避免历史数据干扰 - 重点过滤
event IN ('latch: lob allocation latch', 'PGA memory operation'),并检查session_state = 'WAITING' - 若
sql_id为空但program是 JDBC Thin Client,大概率是应用层反复调用CREATE_TEMPORARY却没配DBMS_LOB.FREETEMPORARY
确认 LOB 段是否真实“挂住”在内存中
DBA_LOBS 查不到临时 LOB,得看 v$tempseg_usage 和 v$process 的交叉线索:临时 LOB 不写磁盘段,但会占用 PGA + UGA 内存,且生命周期绑定到会话或事务。如果会话已断开但 v$tempseg_usage 仍有记录,说明 LOB 句柄泄漏。
- 运行
SELECT session_addr, sql_id, contents, segtype, blocks FROM v$tempseg_usage WHERE segtype = 'LOB_DATA',注意session_addr是否指向已消失的会话(查v$session确认) - 对疑似会话,查
v$process.pga_used_mem和v$session.pga_used_mem是否严重不一致——前者远大于后者,说明 LOB 内存未被会话级回收 - 临时 LOB 的
lob_id在 ASH 里不暴露,但sql_id若频繁出现DBMS_LOB.CREATETEMPORARY字样(通过DBA_HIST_SQLTEXT关联),就是高危信号
区分是应用层泄漏还是 Oracle Bug 导致的无法释放
Oracle 12.1.0.2 之后版本中,DBMS_LOB.CREATETEMPORARY 在 PL/SQL 块退出时本应自动释放,但若块内发生异常未捕获、或用了 PRAGMA AUTONOMOUS_TRANSACTION,释放逻辑会被跳过。这不是连接池问题,而是 PL/SQL 执行环境缺陷。
- 检查对应
sql_id的执行计划是否含TEMP TABLE TRANSFORMATION+LOB操作节点——这类组合在并行环境下容易触发内部句柄残留 - 用
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('xxx', NULL, 'ALLSTATS LAST'))看TempSpc列是否为 0,但实际v$tempseg_usage.blocks持续增长 - 确认数据库补丁级别:
SELECT * FROM v$version;已知 Bug 21555660(12.1.0.2.170117)会导致CREATETEMPORARY后异常退出时不清理 UGA 中的 LOB 描述符
快速验证和止损动作
临时 LOB 泄漏不会立刻 OOM,但会缓慢耗尽共享池中的 lob segment heap,最终导致新 LOB 创建失败报 ORA-1652: unable to extend temp segment。此时不能只 kill 会话,必须清空相关内存结构。
- 立即执行
ALTER SYSTEM FLUSH SHARED_POOL(仅限紧急止血,勿在业务高峰) - 对已确认泄漏的会话,用
ALTER SYSTEM KILL SESSION '<sid>,<serial#>' IMMEDIATE,再查v$tempseg_usage是否清零 - 长期修复必须改代码:所有
CREATETEMPORARY后必须配对FREETEMPORARY,且放在EXCEPTION块中;禁用AUTONOMOUS_TRANSACTION下的 LOB 操作
临时 LOB 的泄漏最难复现,因为它依赖 PL/SQL 执行路径与异常传播顺序,ASH 里留下的痕迹极淡——你看到的往往只是“某个会话 PGA 突然涨了 200MB”,而真正源头藏在 3 层嵌套的匿名块里。


















