本质是子游标(child cursor)爆炸导致遍历匹配严重串行化,version_count过高使Mutex S/X持有时间剧增,引发cursor: mutex S、cursor: mutex X及cursor: pin S wait on X高频等待。
cursor: mutex s、cursor: mutex x、cursor: pin s wait on x 这些等待事件高频出现,本质不是“parent游标等得太多”,而是parent游标下子游标(child cursor)爆炸性增长,导致访问、遍历、匹配过程严重串行化。oracle 从 10g 起用 mutex 替代部分 latch,本意是更轻量,但一旦子游标数量失控,mutex 的持有时间反而变长,争用立刻凸显。
为什么 version_count 高会导致 Parent 级等待激增?
Parent 游标本身不执行,它只是个哈希桶入口;真正干活的是子游标。当会话要执行一条 SQL,Oracle 必须: - 根据sql_id 定位 Parent
- 遍历该 Parent 下所有子游标(v$sql_shared_cursor 中每一行就是一个 child)
- 对每个 child 检查绑定变量类型、NLS 设置、优化器环境等 20+ 个匹配字段
这个遍历过程在 11gR2 前需持 cursor: mutex X,11gR2 后虽优化为分段加锁,但若 version_count > 100,仍会显著延长 Mutex 持有时间——尤其当多个会话同时请求同一 Parent 下的 child 时,cursor: mutex S 和 cursor: pin S wait on X 就集中爆发。
-
version_count超过 20:AWR 默认列出;超过 50 就该盯紧;超过 100 几乎必然引发争用 - 常见诱因:
NLS_LANGUAGE/NLS_TERRITORY不一致、绑定变量窥视(bind-aware cursor)、optimizer_features_enable动态切换、cursor_sharing = FORCE生成非标准文本 - 注意:
v$sql.version_count是瞬时快照,可能在你查询时已被老化;应结合 AWR 报告中 “SQL ordered by Version Count” 页面确认历史峰值
如何快速定位是哪个 SQL 的 Parent 在拖慢全局?
别只看v$system_event 总等待时间,要抓“热 Parent”的真实 SQL 文本和环境差异:
-
查当前高 version_count 的活跃 SQL:
SELECT sql_id, version_count, sql_text FROM v$sql WHERE version_count > 50 AND loaded_versions > 0 ORDER BY version_count DESC FETCH FIRST 5 ROWS ONLY;
-
查该 SQL 子游标分裂原因(关键!):
SELECT sql_id, child_number, bind_mismatch, optimizer_mode_mismatch, nls_mismatch, px_mismatch, slave_mismatch, typecheck_mismatch FROM v$sql_shared_cursor WHERE sql_id = '&sql_id' AND (bind_mismatch = 'Y' OR nls_mismatch = 'Y' OR optimizer_mode_mismatch = 'Y'); 如果发现大量
nls_mismatch = 'Y',说明应用连接未统一ALTER SESSION SET NLS_LANGUAGE=...;;若全是bind_mismatch = 'Y',基本坐实未用绑定变量或绑定值类型不一致(如:id有时传 NUMBER、有时传 VARCHAR2)
为什么 kill session 或 flush shared_pool 只是临时止痛?
-ALTER SYSTEM FLUSH SHARED_POOL 会清空所有游标,但只要应用继续发未绑定变量的 SQL,几秒内就会重建出更多子游标,争用重现
- KILL SESSION 只释放单个会话持有的 Mutex/Pin,而阻塞源往往是后台统计信息收集(DBMS_STATS)或 DDL,它们持 X 锁时间长且不可中断
- 最隐蔽的坑:某些 JDBC 驱动默认开启 implicit caching,但未配 session_cached_cursors,导致每次 execute 都走硬解析 → 新建 child → version_count 暴涨
真正有效的干预点只有三个:统一客户端 NLS 设置、强制绑定变量(哪怕用 cursor_sharing = SIMILAR 也比 EXACT 强)、限制统计信息自动收集范围并设 NO_INVALIDATE => FALSE。
Parent 游标本身不慢,慢的是你让它管了 200 个互不兼容的子游标——这不是 Oracle 的 Bug,是配置和应用行为越界后,轻量级 Mutex 暴露出来的放大效应。


















