Oracle 19c 中 latch: shared pool 竞争高根源是未绑定变量导致硬解析暴增,应通过 v$active_session_history 查最近1分钟 event='latch: shared pool' 的 SQL,结合 v$sql 中 loads>executions、UNBOUND_CURSOR='Y' 及字面量特征确认。
oracle 19c 中 latch: shared pool 竞争高,基本可以断定是硬解析暴增导致的,不是 shared_pool_size 太小、也不是 latch 数量不够——锁争用只是表象,根源在 sql 没绑定变量。
查 ASH 里正在抢 shared pool latch 的活体 SQL
别翻 AWR 报告总硬解析数,那只是结果。要抓“此刻正在争 latch”的语句,v$active_session_history 是唯一能反映真实压力点的视图。它不依赖缓存、不经过聚合,采样的是正在执行的会话。
-
event = 'latch: shared pool'的记录,说明该会话正卡在获取 shared pool latch 上,大概率刚发起或正在进行硬解析 - 必须加时间过滤:
SAMPLE_TIME > SYSDATE - 1/1440(最近 1 分钟),否则默认查全历史,慢且干扰多 - 聚合时按
sql_id+sql_opname分组,避免把 INSERT/UPDATE 混在一起;sql_opname能帮你快速区分是查询还是 DML 引发的解析 - 示例语句直接可用:
SELECT sql_id, sql_opname, COUNT(*) cnt FROM v$active_session_history WHERE event = 'latch: shared pool' AND sample_time > SYSDATE - 1/1440 GROUP BY sql_id, sql_opname ORDER BY cnt DESC FETCH FIRST 10 ROWS ONLY;
验证 SQL 是否真没绑定变量
拿到 top sql_id 后,不能只看执行次数,关键要看它是否因字面量不同而反复触发硬解析。这类 SQL 在 v$sql 里表现为:低 executions、高 loads、频繁 invalidations,且 sql_text 里含连续单引号。
- 查
sql_text是否含字面量:WHERE sql_text LIKE '%''%''%'(注意是两个单引号连写,代表字符串值) - 重点比对
executions和loads:若executions = 1但loads > 5,基本坐实每次换值都重编译 - 检查
v$sql_shared_cursor中对应sql_id的UNBOUND_CURSOR列是否为Y——这是 Oracle 明确标记“无法复用游标”的信号 - 别信
CURSOR_SHARING=FORCE:19c 已标记为desupported,它生成的系统绑定变量会导致 ACS 抖动、子游标爆炸,反而拉长 hash chain、加重 latch 争用
避开常见误判和无效操作
很多 DBA 一看到 shared pool latch 高,就去调大 shared_pool_size 或 flush shared_pool,这不仅无效,还可能让问题更隐蔽。
-
RESULT_CACHE对缓解latch: shared pool基本无效:它缓存结果,不减少硬解析;其元数据本身也受 shared pool latch 保护,高并发下可能加剧争用 -
v$sgastat中free memory低于 5MB 是碎片化信号,但不是扩容理由——空闲块分散、单个不够用时,扩大会让碎片更难整合 -
DBA_HIST_ACTIVE_SESS_HISTORY不适合定位瞬时争用:它的采样延迟可达 10 秒,且默认只保留 1 小时快照;优先跑v$active_session_history - 应用端 JDBC 必须禁用
implicitCache,Python cx_Oracle 必须避免重复调用cursor.prepare();prepare 一次、execute 多次才是正确姿势
真正难的不是查到哪条 SQL 在硬解析,而是确认它是否由触发器、动态 SQL 或 ORM 自动生成——这些场景下 sql_id 可能为空,或 program_id 指向 PL/SQL 单元,需要交叉查 dba_objects 才能定位源头。


















