运维管理10 分钟阅读
Oracle library cache 等待怎么查?Lock、Pin、Mutex 一次讲清楚
2026年10月15日阅读—点赞—收藏—
OracleLock
在知识库中专注阅读,并随时返回相关工具与课程
前面写 Oracle 等待事件那篇文章时,留言区有用户提到了 library cache,希望我能详细聊聊,其实这类等待和普通的 I/O、行锁等待不太一样。
比如 db file sequential read,可以从读取量和 I/O 延迟入手;enq: TX - row lock contention,通常先找阻塞会话。
但如果 AWR 里面出现下面几个事件:
1library cache lock2library cache pin3library cache load lock4library cache: mutex X5cursor: pin S wait on X排查起来就没那么直接了。
这些事件虽然都和 Library Cache 有关,但等待的资源并不相同。尤其是 library cache lock 和 library cache pin,名字只有一个单词的区别,涉及的机制却不一样。
这篇把相关原理和常用排查方法整理一下,以 Oracle 19c 为例。
Oracle 的 SGA 中有一块 Shared Pool,而 Library Cache 是 Shared Pool 的重要组成部分。
SQL 解析后的游标、执行计划,以及 PL/SQL 程序单元等相关信息,都可能保存在 Library Cache 中。
比如应用执行:
1SELECT * FROM TEST_TABLE WHERE ID = :1;Oracle 需要解析 SQL,查找是否存在可以复用的游标,并检查对象、权限及相关依赖。如果能够复用,就不需要每次都重新完成硬解析。
不过,这些缓存对象可能同时被多个会话使用。
假设一个会话正在执行某个存储过程,另一个会话准备重新编译这个过程,Oracle 就需要协调对相关 Library Cache 对象的访问。
这也是 Library Cache 中存在 Lock、Pin 和 Mutex 等机制的原因。
这是最容易混淆的两个事件。
library cache lock:它主要用于协调 Library Cache 对象句柄的访问,以及维护对象之间的依赖关系。
比如某个会话正在使用一个对象,另一个会话准备修改该对象,可能需要等待相关的 Library Cache Lock。
library cache pin:它主要用于保护对象在 Library Cache 中的具体内容。会话需要访问或修改对象内容时,通常需要在取得相应 Lock 后,再取得 Pin。
可以简单理解为:
当然,Oracle 内部实现比这个复杂,不能简单把 Lock 理解成表锁,也不能把 Pin 理解成行锁。
这两种等待也不属于 enq: TX 那套事务行锁机制。
官方文档:Oracle Database 19c — Descriptions of Wait Events
对应章节:
比较常见的场景是对象发生变更。
例如一个存储过程正在被应用调用,同时有人执行:
1ALTER PROCEDURE TEST_PROC COMPILE;如果对象正在被其他会话使用,重新编译就可能需要等待相关 Library Cache 资源。反过来,如果某个会话正在编译或修改对象,其他需要访问该对象的会话也可能受到影响。
类似情况还可能出现在:
不过,具体出现哪一种等待事件,要看当时争用的资源和操作,不能简单认为执行 DDL 就一定产生 library cache lock。
library cache load lock 主要出现在对象加载过程中。Oracle 为避免多个进程同时加载同一个对象,需要获取独占的 Load Lock。如果其他会话正在加载该对象,当前会话就可能等待。它和普通的 library cache lock 不是同一种机制。
Oracle 还有一些比较常见的相关等待:
1library cache: mutex X2cursor: pin S wait on X这里涉及 Mutex(互斥机制)。
library cache: mutex X 表示会话在获取 Library Cache 相关结构的独占 Mutex 时发生等待,可能涉及对象查找、游标管理及并发解析等操作。实际排查时,还需要结合等待参数和 SQL 解析情况判断具体争用点。
cursor: pin S wait on X 表示当前会话需要获取游标的共享 Mutex Pin,但其他会话正以独占模式持有该资源,因此只能等待。这个事件通常需要结合 SQL 解析、游标共享和并发访问情况进一步分析。
因此,虽然它们都可能出现在 SQL 解析或执行过程中,但不能把 Mutex 等待和 library cache lock、library cache pin 混为一谈。
实际排查时,如果是 Mutex 类等待,我会更关注 SQL 解析频率、游标共享、子游标数量以及是否存在大量并发解析。如果是 Lock 或 Pin 等待,则需要进一步检查对象变更、失效、重新编译及持有相关资源的会话。
下面整理几条 Oracle 19c 常用的查询语句,先从实时会话入手。
1SELECT inst_id,2 sid,3 serial#,4 username,5 event,6 state,7 ROUND(wait_time_micro / 1000000, 3) AS wait_sec,8 sql_id,9 blocking_instance,10 blocking_session,11 module,12 program13FROM gv$session14WHERE state = 'WAITING'15 AND (16 event LIKE 'library cache%'17 OR event LIKE 'cursor: pin%'18 )19ORDER BY wait_time_micro DESC;先查看当前有哪些会话正在等待 Library Cache 相关资源,以及等待已经持续了多久。
如果多个会话集中在同一个等待事件或 SQL_ID 上,可以进一步检查等待参数和阻塞关系。BLOCKING_SESSION 可以作为参考,但并不是所有 Library Cache 等待都能直接通过它找到持有者。
1SELECT inst_id,2 sid,3 event,4 p1text,5 p1,6 p1raw,7 p2text,8 p2,9 p2raw,10 p3text,11 p3,12 sql_id13FROM gv$session14WHERE state = 'WAITING'15 AND event IN (16 'library cache lock',17 'library cache pin',18 'library cache load lock'19 );对于 library cache lock 和 library cache pin,P1 通常是对象的 Handle Address。这个地址非常重要,因为后面可以尝试通过它关联到具体 Library Cache 对象。
但需要注意,不同等待事件的 P1、P2、P3 含义并不相同,不能把 Mutex 类等待的参数也按照相同方式解释。
Oracle 的 V$DB_OBJECT_CACHE 可以查看 Library Cache 中的对象信息:
1SELECT s.inst_id,2 s.sid,3 s.serial#,4 s.event,5 s.sql_id,6 RAWTOHEX(s.p1raw) AS wait_handle,7 o.owner,8 o.name,9 o.type,10 o.namespace11FROM gv$session s12LEFT JOIN gv$db_object_cache o13 ON o.inst_id = s.inst_id14 AND o.addr = s.p1raw15WHERE s.state = 'WAITING'16 AND s.event IN (17 'library cache lock',18 'library cache pin'19 )20ORDER BY s.inst_id, s.sid;这条 SQL 通过等待会话的 P1RAW 与 GV$DB_OBJECT_CACHE.ADDR 关联,尝试找到发生等待的 Library Cache 对象。对于 RAC,需要通过 INST_ID 确保关联的是同一个实例的数据。
1SELECT l.inst_id,2 l.type,3 RAWTOHEX(l.object_handle) AS object_handle,4 RAWTOHEX(l.holding_session) AS holding_session,5 RAWTOHEX(l.holding_user_session) AS holding_user_session,6 s.sid,7 s.serial#,8 s.username,9 s.status,10 s.sql_id,11 s.event,12 l.mode_held,13 l.mode_requested14FROM gv$libcache_locks l15LEFT JOIN gv$session s16 ON s.inst_id = l.inst_id17 AND s.saddr = l.holding_user_session18WHERE l.inst_id = :inst_id19 AND l.object_handle = HEXTORAW(:handle_hex)20ORDER BY l.type,21 l.mode_requested DESC,22 l.mode_held DESC;这条 SQL 根据对象 Handle 查询相关的 Library Cache Lock/Pin,查看资源的持有模式和请求模式,并尝试关联到具体会话。
HOLDING_SESSION 和 HOLDING_USER_SESSION 都是内部地址,不是 SID。
这里使用 HOLDING_USER_SESSION 与 GV$SESSION.SADDR 关联,但并不保证所有记录都能找到对应会话。如果关联不到,还需要结合内部会话地址和其他诊断信息进一步分析。
另外,RAC 中这些内存地址属于具体实例,不能拿实例 1 的地址去实例 2 中查。
1SELECT owner,2 name,3 type,4 loads,5 executions,6 invalidations7FROM v$db_object_cache8WHERE invalidations > 09ORDER BY invalidations DESC10FETCH FIRST 30 ROWS ONLY;如果某些对象存在较多 Invalidations,可以进一步检查近期是否发生过 DDL、对象重新编译或依赖对象变更。但 INVALIDATIONS 是累计计数,不能只凭数值高就判断它是当前等待的原因。
1SELECT name,2 value3FROM v$sysstat4WHERE name IN (5 'parse count (total)',6 'parse count (hard)',7 'execute count'8)9ORDER BY name;这几个指标也是累计值,最好结合 AWR 的快照增量,判断异常时段解析次数是否明显增加。
如果出现大量 library cache: mutex X 或 cursor: pin S wait on X,可以进一步检查 V$SQL 中的版本数、解析调用次数和 SQL 共享情况。
实时查询有一个明显的问题:等 DBA 开始排查时,等待可能已经消失了。
这时候就需要使用 ASH。
例如检查某个时间段内的 Library Cache 相关等待:
1SELECT instance_number,2 sample_time,3 session_id,4 session_serial#,5 sql_id,6 event,7 blocking_inst_id,8 blocking_session,9 p1text,10 p1,11 p2,12 p313FROM dba_hist_active_sess_history14WHERE sample_time >=15 TO_TIMESTAMP(:begin_time, 'YYYY-MM-DD HH24:MI:SS')16 AND sample_time <17 TO_TIMESTAMP(:end_time, 'YYYY-MM-DD HH24:MI:SS')18 AND session_state = 'WAITING'19 AND (20 event LIKE 'library cache%'21 OR event LIKE 'cursor: pin%'22 )23ORDER BY sample_time, instance_number;这条 SQL 用于查看指定时间段内的历史 ASH 记录,包括等待事件、SQL_ID、会话信息、等待参数以及可能存在的阻塞会话。
需要注意,ASH 采用采样方式记录活跃会话,并不会保存每一次等待。DBA_HIST_ACTIVE_SESS_HISTORY 中的数据也可能经过进一步抽样,因此短时间内发生的等待不一定能查到。
如果发现某个时间段内有大量会话集中等待同一个事件,可以继续结合 SQL_ID、等待参数、阻塞会话和业务操作时间,进一步缩小排查范围。
第一个是看到 Library Cache 等待就增加 Shared Pool。
Shared Pool 空间不足确实可能带来解析和缓存管理问题,但 Library Cache 等待也可能是对象变更、依赖关系或游标并发竞争造成的。
没有证据之前,直接增加 shared_pool_size 不一定有效。
第二个是发现等待会话后就准备 Kill Session。
Library Cache 等待的持有者不一定能通过 GV$SESSION.BLOCKING_SESSION 直接找到。即使找到相关会话,也需要先确认它正在执行什么操作。
如果正在进行对象编译、DDL 或重要业务操作,贸然终止可能带来额外影响。
第三个是直接执行 ALTER SYSTEM FLUSH SHARED_POOL。
这类操作可能导致大量游标失效和后续硬解析,生产环境不应该把它作为常规处理手段。
Library Cache 相关等待比普通 I/O 等待复杂一些,主要是因为它涉及对象依赖、解析、编译以及多个会话之间的并发访问。
我觉得排查时可以先把事件分清楚:
library cache lock、library cache pin 重点关注对象访问和变更;library cache: mutex X、cursor: pin S wait on X 则需要更多关注游标和解析相关的并发竞争。后面再通过等待参数、对象 Handle、SQL_ID 和 ASH 逐步定位。
至于具体是什么原因,还是要结合现场数据判断,不能只根据等待事件名称下结论。