awr报告中library cache lock高占比表明已形成固化瓶颈,必须用gv$active_session_history定位持锁会话而非仅看awr排名;关键查sql_opname为ddl且p1text='handle address'、p2text='lock address'的记录,rac环境须用gv$视图避免跨节点漏查。

AWR 报告里出现 library cache lock 等待,说明不是瞬时毛刺,而是已固化为性能瓶颈——必须从 ASH 定位持锁源头,而非只看 AWR 的“等待事件排名”。
为什么不能只看 AWR 的 Top Event
AWR 汇总的是采样窗口内的等待总和,但 library cache lock 是典型的“阻塞链传播型”等待:一个会话持锁 30 秒,可能造成上百个会话累计等待数小时。AWR 只告诉你“等得久”,不告诉你“谁在锁、锁什么、为什么不放”。
更危险的是,AWR 中该事件排高,常伴随 library cache: mutex X 或 cursor: pin S wait on X —— 这些是连锁反应,根因不在它们身上。
用 GV$ACTIVE_SESSION_HISTORY 直接揪出持锁会话
关键不是查“谁在等”,是查“谁在持锁且没释放”。执行以下查询(RAC 必须用 GV$):
SELECT sql_id, sql_opname, event, p1text, p1, p2text, p2, blocking_session, session_state
FROM gv$active_session_history
WHERE event = 'library cache lock'
AND sample_time > SYSDATE - 1/24
AND sql_opname IN ('ALTER', 'CREATE', 'DROP', 'GRANT', 'REVOKE')
ORDER BY sample_time DESC;
-
p1text = 'handle address'且p2text = 'lock address'的行,才是真实持锁点 - 若
blocking_session非空,且对应会话的sql_opname是CREATE OR REPLACE PACKAGE或ALTER VIEW,基本锁定根因 -
sql_id为空?别停——立刻用session_id关联v$session查sql_text,DDL 编译阶段常无sql_id
确认对象是否真被卡住:查 v$db_object_cache
持锁会话指向的对象,很可能已在共享池中“挂起”。执行:
SELECT name, type, locks, kept
FROM v$db_object_cache
WHERE name = 'PKG_NAME'
AND type IN ('PACKAGE', 'PROCEDURE', 'FUNCTION');
-
locks > 0表示该对象当前被加锁,且未释放 -
kept = 'NO'说明它可被老化淘汰,但因锁未释放,无法清理 - 若
type = 'PACKAGE BODY'且locks = 1,大概率是CREATE OR REPLACE PACKAGE BODY卡在依赖校验或编译阶段
RAC 环境下最容易忽略的跨节点陷阱
RAC 中 library cache lock 等待常跨节点发生,但 ASH 默认只查本节点。漏掉其他节点的持锁会话,等于没查:
- 必须在所有节点上分别运行上述
GV$ACTIVE_SESSION_HISTORY查询;或确保使用的是全局视图(GV$前缀已隐含跨节点) - 检查
v$lock中TYPE = 'AE'(application enqueue)和TYPE = 'RT'(redo thread),它们常与未提交 DDL 关联,且跨节点可见 - 禁止在 RAC 中执行
ALTER SYSTEM FLUSH SHARED_POOL—— 这是广播操作,会瞬间触发全节点硬解析洪流,把问题放大十倍
真正要做的,是用 DBMS_SHARED_POOL.PURGE('PKG_NAME', 'P') 精准清理特定对象,而不是清整个池。











