cursor: pin S wait on X 是游标争用问题,需通过 AWR 的“SQL Ordered by Version Count”和“Parse Calls”定位高 version_count 与高解析率 SQL,结合 dba_hist_active_sess_history 查 blocking_session 及 p2 解析持 X pin 会话,并用 v$sql_shared_cursor 分析 BIND_MISMATCH 等不共享原因。

这不是锁表问题,而是多个会话争抢同一个 SQL 游标的共享访问权——cursor: pin S wait on X 在 AWR 报告里排高,说明软解析失败或硬解析风暴已成瓶颈,90% 以上能定位到具体 sql_id 和绑定变量行为。
从 AWR 报告快速圈出罪魁 SQL
AWR 太粗,不能只看 “Top 5 Events” 里 cursor: pin S wait on X 的等待时间总和。关键要进 “SQL Ordered by Version Count” 和 “SQL Ordered by Parse Calls” 两个板块:
- 若某条 SQL 的
version_count> 20,且loaded_versions持续跳变,基本确认游标已碎成一地 - 对比同一 SQL 的
Executions和Parse Calls:若后者 / 前者 > 0.1(即每 10 次执行就有 1 次解析),就是软解析失控信号 - 注意 “SQL with Top Events” 表格里,过滤
Event = 'cursor: pin S wait on X',直接看到哪些sql_id正在引发阻塞链
查 blocking_session 定位持 X pin 的会话
别只盯着等待的会话,真正要抓的是那个长期以排他模式(X)pin 住游标的“钉子户”。在 AWR 时间窗口内执行:
SELECT sid, blocking_session, sql_id, event, p1, p2
FROM dba_hist_active_sess_history
WHERE event = 'cursor: pin S wait on X'
AND sample_time BETWEEN TO_DATE('2026-07-20 14:00', 'yyyy-mm-dd hh24:mi')
AND TO_DATE('2026-07-20 14:15', 'yyyy-mm-dd hh24:mi')
AND blocking_session IS NOT NULL;对每个非空 blocking_session,查它当时执行的语句:
SELECT sql_id, sql_text FROM dba_hist_active_sess_history s JOIN dba_hist_sqltext t ON s.sql_id = t.sql_id WHERE s.session_id = &blocking_sid AND ROWNUM = 1;
p2 值含隐藏线索:64 位库中,TRUNC(&p2/4294967296) 就是持 X pin 的 SID;若结果为 0,可能是后台进程或 internal operation,需结合 program 和 machine 判断
用 v$sql_shared_cursor 看游标不共享的真实原因
v$sqlarea 只告诉你“碎了”,v$sql_shared_cursor 才告诉你“为什么碎”。对高 version_count 的 sql_id 执行:
SELECT * FROM v$sql_shared_cursor WHERE sql_id = '&sql_id' AND (BIND_MISMATCH = 'Y' OR OPTIMIZER_MISMATCH = 'Y' OR TRANSLATION_MISMATCH = 'Y');
重点关注这几列:
-
BIND_MISMATCH = 'Y':绑定变量类型/长度不一致(如VARCHAR2(1)vsVARCHAR2(32)),最常见 -
OPTIMIZER_MISMATCH = 'Y':优化器环境不同(optimizer_mode、optimizer_features_enable、统计信息陈旧) -
TRANSLATION_MISMATCH = 'Y':NLS 设置或字符集差异(客户端传了不同NLS_LANG)
动态采样也会触发 OPTIMIZER_MISMATCH:大表无统计信息时,首次硬解析会触发耗时的动态采样,导致持 X pin 时间异常长
绕过解析争用的实操手段
临时缓解比等 DBA 改参数更快:
- 加 hint 强制跳过动态采样:
SELECT /*+ dynamic_sampling(0) */ COUNT(*) FROM big_table - 用
DBMS_SHARED_POOL.KEEP固化高频 SQL:EXEC DBMS_SHARED_POOL.KEEP('8duehra3kdx62', 'C')('C'表示 cursor) - 紧急关闭动态采样(慎用):
ALTER SYSTEM SET optimizer_dynamic_sampling = 0,但必须同步补全所有 SQL 的 hint 或统计信息,否则执行计划可能劣化 - 检查应用是否漏写绑定变量:相同逻辑 SQL 出现多个
sql_id(文本相似但 hash 不同),基本可断定是字面量拼接
真正难的不是定位,而是确认那个 BIND_MISMATCH 是来自 JDBC 驱动自动推断、还是应用层显式声明缺失——这往往藏在连接池配置或 ORM 框架默认行为里,不在数据库视图中暴露。


















