oracle 19c中latch: shared pool高争用根源是未绑定变量导致硬解析暴增,应通过v$active_session_history查最近1分钟event='latch: shared pool'的sql,结合v$sql中loads>executions、unbound_cursor='y'及字面量特征精准定位。

查 v$active_session_history 中正在抢 latch: shared pool 的活体 SQL
硬解析争用不是“历史累计高”,而是“此刻正卡在 latch 上”。v$active_session_history 是唯一能抓到真实争用瞬间的视图,比 AWR 或 v$sql 更直接。
必须加时间过滤,否则默认查全历史,慢且干扰多:
• SAMPLE_TIME > SYSDATE - 1/1440(最近 1 分钟)
• 按 sql_id 和 sql_opname 分组,避免把 SELECT 和 UPDATE 混在一起
• 只取 event = 'latch: shared pool' 的记录,这是硬解析卡点的明确信号
示例语句可直接执行:
SELECT sql_id, sql_opname, COUNT(*) cnt<br>FROM v$active_session_history<br>WHERE event = 'latch: shared pool'<br> AND sample_time > SYSDATE - 1/1440<br>GROUP BY sql_id, sql_opname<br>ORDER BY cnt DESC<br>FETCH FIRST 10 ROWS ONLY;
验证拿到的 sql_id 是否真因字面量导致硬解析
不能只看执行次数,关键看它是否每次换值都重编译。这类 SQL 在 v$sql 中有三个典型特征:
• executions = 1 但 loads > 5:说明几乎没复用,每次都在硬解析后被挤出共享池
• sql_text LIKE '%''%''%'(注意是两个单引号连写):代表含字符串字面量,如 WHERE name = 'Alice'
• UNBOUND_CURSOR = 'Y' 在 v$sql_shared_cursor 中:Oracle 明确标记“无法复用游标”
别信 CURSOR_SHARING = FORCE:19c 已标记为 desupported,它会生成系统绑定变量,反而引发 ACS 抖动和子游标爆炸,拉长 hash chain,加重 latch 争用。
避开无效操作:调大 shared_pool_size 或 flush shared_pool 反而更糟
这些动作解决不了根源问题,还可能让现象更隐蔽:
• shared_pool_size 过大会导致 LRU 链变长、hash bucket 查找变慢,甚至触发 library cache: mutex X 新争用
• flush shared_pool 会清空所有缓存,强制后续所有 SQL 全量硬解析,瞬间引爆 latch: shared pool
• RESULT_CACHE 对缓解该问题基本无效:它缓存结果,不减少硬解析;其元数据本身也受 shared pool latch 保护
真正有效的路径只有一条:定位到未绑定变量的 SQL,推动应用层改用 :b1 类占位符,而不是拼接字面量。
为什么 ASH 比 AWR 更适合抓硬解析源头
AWR 报告里的 Execute to Parse % 低于 90% 是预警信号,但它只能告诉你“解析多了”,不能告诉你“谁在抢 latch”。而 ASH 的采样机制决定了:
• 每条 event = 'latch: shared pool' 记录,都对应一个真实会话正卡在获取 shared pool latch 的瞬间
• 它不依赖缓存、不经过聚合,不丢失上下文(比如 sql_opname、session_state)
• 即使 SQL 执行极快(容易被忽略的一点:如果发现大量 latch: shared pool 等待但 sql_id 为空,要检查是否是匿名 PL/SQL 块(如 EXECUTE IMMEDIATE 'select ... where id = '||i),这种场景下 sql_opname 往往是 PL/SQL EXECUTE,需结合 plsql_entry_object_id 追踪来源。











