根本原因是应用未绑定变量导致大量硬解析;应通过v$active_session_history查最近1分钟争shared pool latch的sql,按sql_id和sql_opname分组定位,并验证v$sql中loads>5且executions=1、sql_text含字面量、unbound_cursor='y'。

这不是插入本身的问题,而是插入前或插入过程中触发了大量硬解析——根本原因几乎总是应用没绑定变量。
查正在争shared pool latch的SQL
别翻AWR总硬解析数,那只是结果。要抓“此刻正在抢latch”的语句,v$active_session_history是唯一能反映真实压力点的视图。
- 必须加时间过滤:
SAMPLE_TIME > SYSDATE - 1/1440(最近1分钟),否则默认查全历史,慢且干扰多 - 按
sql_id和sql_opname分组,避免把INSERT和SELECT混在一起 - 直接执行这个语句定位源头:
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是否真没绑定变量
拿到sql_id后,不能只看执行次数。关键看它是否因字面量不同反复触发硬解析。
- 查
v$sql:若executions = 1但loads > 5,基本坐实每次换值都重编译 - 查
sql_text是否含字面量:WHERE sql_text LIKE '%''%''%'(注意是两个单引号连写) - 查
v$sql_shared_cursor中对应sql_id的UNBOUND_CURSOR列是否为Y——这是Oracle明确标记“无法复用游标”的信号
别碰shared_pool_size或flush shared_pool
调大shared_pool_size不仅无效,还会让问题更隐蔽:chunk更多、hash chain更长、latch持有时间反而增加。
-
CURSOR_SHARING=FORCE在19c已标记为desupported,它生成的系统绑定变量会导致ACS抖动、子游标爆炸,加重latch争用 -
RESULT_CACHE对缓解latch: shared pool基本无效:它缓存结果,不减少硬解析;其元数据本身也受shared pool latch保护 - 真正有效的动作发生在应用层:JDBC必须复用
PreparedStatement并调用clearParameters(),Python cx_Oracle要避免在循环内重复cursor.prepare()
最容易被忽略的是:并发插入慢的表象下,往往藏着一批高频执行、仅WHERE条件字面量不同的SELECT语句——它们才是硬解析主力,而INSERT只是被拖累的“背锅侠”。











