快速定位争抢sql和子游标需查v$session_wait实时等待,取p1(hash_value)关联v$sqlarea看version_count>10即游标严重分裂;绑定变量未显式声明类型/长度会导致bind_mismatch='y',查v$sql_bind_capture和v$sql_shared_cursor确认;cursor: pin s wait on x需用blocking_session定位持锁会话,纯cursor: pin s则关注cpu与执行频次。

怎么快速定位正在争抢的 SQL 和子游标
直接查实时活跃等待点,别只翻 AWR 报告——cursor: pin S 是 CPU 级 mutex 争用,等不到采样周期就过去了。
- 执行
SELECT p1, p2, COUNT(*) FROM v$session_wait WHERE event = 'cursor: pin S' GROUP BY p1, p2 ORDER BY COUNT(*) DESC,取前几行的p1(即hash_value) - 用该
p1关联v$sqlarea:SELECT sql_id, sql_text, version_count, loaded_versions FROM v$sqlarea WHERE hash_value = &p1 - 若
version_count > 10,说明子游标链已严重分裂,遍历它本身就会放大 mutex 持有时间
注意:sql_text 显示为 table_x_x_x_x 这类是内部游标,需查 MOS Note:1298471.1,不是你写的 SQL。
为什么绑了变量还是软解析失败
绑定变量没显式声明类型或长度,Oracle 就会按每次传入值推断 VARCHAR2 长度,比如传 'A' 推成 VARCHAR2(1),传 'ABC' 推成 VARCHAR2(3),触发 BIND_MISMATCH = 'Y',强制生成新子游标。
- 查证据:
SELECT child_number, datatype_string, max_length FROM v$sql_bind_capture WHERE sql_id = '&sql_id'—— 若同一sql_id下出现多个不同datatype_string或max_length,就是隐患 - 查确认:
SELECT * FROM v$sql_shared_cursor WHERE sql_id = '&sql_id' AND bind_mismatch = 'Y' - JDBC 中必须用
setString(int, String, int)显式传长度;PL/SQL 中避免EXECUTE IMMEDIATE ... USING v_str(v_str是未定长VARCHAR2),改用TO_CHAR()或提前转NUMBER
怎么区分是 wait on X 还是纯 pin S
cursor: pin S wait on X 表示有会话正以排他模式持锁(比如在硬解析、DDL、统计信息刷新),而其他会话卡在共享请求上;纯 cursor: pin S 更可能是高并发下对同一子游标的 mutex 原子操作排队,不涉及 X 锁持有者。
- 查阻塞源:
SELECT sid, blocking_session, sql_id FROM v$session WHERE event = 'cursor: pin S wait on X'(19c+ 直接有blocking_session字段) - 查持锁会话干啥:
SELECT sql_id, sql_text, program FROM v$session s JOIN v$sqlarea a ON s.sql_id = a.sql_id WHERE s.sid = &blocking_sid - 若持锁会话的
sql_id对应version_count > 5且v$sql_shared_cursor里OPTIMIZER_MISMATCH或TRANSLATION_MISMATCH为Y,大概率是统计信息刚刷完导致批量游标失效
纯 cursor: pin S 场景下,v$session_wait.p2 的高位通常不指向有效 SID,而是引用计数,这时重点看 CPU 使用率和单条 SQL 的每秒执行频次。
临时缓解但不改代码时怎么做
当应用无法立刻规范绑定或上线周期长,可用“文本分流”绕过 mutex 竞争热点,本质是让相同逻辑落在不同父游标下,分散子游标链。
- 对热点 SQL 加稳定注释分流,例如原语句
SELECT * FROM orders WHERE id = :1,拆成两组:SELECT /*+ SHARD_1 */ * FROM orders WHERE id = :1和SELECT /*+ SHARD_2 */ * FROM orders WHERE id = :1 - 增大
session_cached_cursors(如从 50 改为 200),减少重复打开游标动作,间接降低 mutex 请求频次 - 19c 及以上建议升级到 19.20+,修复了 mutex 释放延迟的已知 Bug(Bug 32876541)
真正难的不是定位,而是验证修改后是否真的压住了子游标分裂——必须在业务高峰时段盯紧 v$sqlarea.version_count 和 v$sql_shared_cursor.bind_mismatch 的变化,而不是只看等待事件是否消失。











