这不是锁表问题,而是多个会话争抢同一SQL游标共享访问权,根源多为软解析失败或硬解析风暴;需通过blocking_session定位持X pin会话,结合v$sqlarea和v$sql_shared_cursor分析游标分裂与不共享原因,并借助ASH报告秒级定位。
直接结论:这不是锁表问题,而是多个会话争抢同一个 sql 游标的共享访问权,根源几乎总是软解析失败或硬解析风暴——90% 以上案例可定位到具体 sql 和绑定变量行为。
查当前正在阻塞的会话和它持有的 SQL
等待事件本身不告诉你谁在“作恶”,得反查持有 X pin 的会话。别只看 v$session 的 event = 'cursor: pin S wait on X',重点是它的 blocking_session 字段:
- 先执行:
SELECT sid, blocking_session, sql_id, event, p1, p2 FROM v$session WHERE event = 'cursor: pin S wait on X' AND blocking_session IS NOT NULL; - 对每个非空
blocking_session,查它当前执行的语句:SELECT sql_id, sql_text FROM v$session s JOIN v$sqlarea a ON s.sql_id = a.sql_id WHERE s.sid = &blocking_sid; -
p2值含隐藏线索:64 位库中,TRUNC(&p2/4294967296)就是持有者 SID;若结果为 0,说明不是常规会话(可能是后台进程或 internal operation)
验证该 SQL 是否游标分裂严重
找到可疑 sql_id 后,立刻检查它是否已“碎成一地”:
- 运行:
SELECT version_count, loaded_versions, open_versions, users_executing FROM v$sqlarea WHERE sql_id = '&sql_id'; -
version_count > 5是黄灯,> 20 是红灯;若users_executing很高但open_versions持续波动,基本确认是软解析反复失败 - 真正关键的是
v$sql_shared_cursor:SELECT * FROM v$sql_shared_cursor WHERE sql_id = '&sql_id' AND (reason IS NOT NULL OR OPTIMIZER_MISMATCH = 'Y' OR BIND_MISMATCH = 'Y');—— 重点关注BIND_MISMATCH、TRANSLATION_MISMATCH、OPTIMIZER_MISMATCH列为Y的行
ASH 报告里快速圈定时间窗口与 Top Blocking Session
AWR 报告太粗,ASH(Active Session History)才是秒级定位利器。用 awrsqrpt.sql 或 OEM 导出最近 15 分钟的 ASH 报告后,盯住两个板块:
- Top Blocking Sessions:看 “% Activity” 最高的那个 SID,它大概率就是长期持 X pin 的“钉子户”;注意 RAC 环境下要确认实例号,别跨节点查错视图
-
Top SQL with Top Events:过滤事件为
cursor: pin S wait on X的 SQL,对比其 “Executions” 和 “Parse Calls” —— 若后者远高于前者(比如 1000 次 parse / 10 次 exec),就是应用层未复用游标 - 别忽略
sql_plan_hash_value变化:同一sql_id出现多个 plan hash,常伴随OPTIMIZER_MISMATCH,说明统计信息更新或绑定变量窥探引发重解析
调整解析策略:从绑定变量声明到 cursor_sharing
修复不能只靠 DBA,开发配合最关键。以下动作按优先级排序:
- 强制显式声明绑定变量类型和长度:Java 用
setString(1, "val")改为setNString(1, "val")或指定setCharacterStream;PL/SQL 中避免:b1 VARCHAR2模糊声明,改用:b1 VARCHAR2(32) - 检查
cursor_sharing设置:设为FORCE能缓解部分硬解析,但可能引入非最优执行计划;SIMILAR在 12c 已废弃,别用 - 禁用不必要的自动任务:临时停掉
auto optimizer stats collection(尤其在业务高峰前),避免批量游标失效;用DBMS_AUTO_TASK_ADMIN.DISABLE控制 - 慎用
ALTER SYSTEM FLUSH SHARED_POOL:这会把所有游标清空,重启后第一波请求全变硬解析,反而触发更猛烈的cursor: pin S wait on X风暴
最易被忽略的一点:游标共享失败往往藏在“看起来一样”的 SQL 里——客户端字符集差异、NLS_DATE_FORMAT 不一致、甚至 JDBC 驱动版本不同,都可能导致 v$sql_shared_cursor.TRANSLATION_MISMATCH = 'Y'。不要只盯着 SQL 文本是否相同,得进 v$sql_shared_cursor 逐列比对。











