oracle 12c中library cache lock高占比主因是硬解析失控或对象编译冲突,非共享池大小问题;须通过v$session定位阻塞链、p1raw关联x$kglob查对象,并分层干预(如停统计任务、禁用非绑定变量sql)根治。
oracle 12c 中出现 library cache lock 等待事件且占比高(如超过总等待时间的 50%),基本可以断定是硬解析失控或对象编译冲突,不是共享池大小问题——调大 shared_pool_size 通常无效,甚至可能延缓问题暴露。
查阻塞源头:别只看 v$session_wait
直接查 v$session_wait 只能看到“谁在等”,但看不到“被谁挡着”。必须结合阻塞链定位真正的持有者:
- 先执行
SELECT sid, blocking_session, event, p1raw, p2raw FROM v$session WHERE event = 'library cache lock' AND state = 'WAITING'找出所有等待会话及它们的blocking_session - 对每个非空的
blocking_session,查v$session对应的sql_id、program、machine和logon_time,重点关注是否为DBMS_STATS、PL/SQL编译、或长时间未提交的 DDL - 特别注意
p1raw值:它是 handle address,可用来关联x$kglob查对象类型。例如SELECT kglhdnsp, kglnaobj FROM x$kglob WHERE kglhdadr = 'C000000122E2A6D8'(把p1raw值代入) - 如果
blocking_session是空的,说明持有者已断开但锁未释放(常见于异常退出的 SQL*Plus 会话),此时需查v$access或dba_ddl_locks辅助判断
快速缓解:kill 还是 disable?
在业务不可中断场景下,盲目 kill session 可能触发回滚风暴或留下 orphaned transaction;更稳妥的做法是分层干预:
- 若阻塞者是统计信息收集任务(
DBMS_STATS),优先执行EXEC DBMS_STATS.STOP_STATS_JOB(12c+ 支持),比 kill 更干净 - 若阻塞者是某个 PL/SQL 包编译(
CREATE OR REPLACE PACKAGE),且确认无并发调用,可用ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE,避免ROLLBACK等待 - 若阻塞者来自应用侧大量非绑定变量 SQL(如
WHERE order_id = 123),临时启用绑定变量捕获:执行ALTER SYSTEM SET cursor_sharing = FORCE,但仅限应急,事后必须改应用代码 - 绝对不要对
PMON、MMAN、QMNC等后台进程执行 kill,它们持有关键库缓存锁时 kill 会导致实例挂起
根因修复:盯死三类高频触发点
Oracle 12c 的 library cache lock 有明确的模式化成因,修复要落在具体动作上,而非泛泛优化:
-
非绑定变量 SQL:用 AWR 报告中的
SQL ordered by Version Count定位版本数 > 100 的语句;检查其sql_text是否含字面值(如日期、ID);强制要求开发使用:bind_var,禁用动态拼接 IN 列表(WHERE id IN ('1','2')→ 改用临时表或sys.odcinumberlist) -
自动任务冲突:12c 默认开启
auto optimizer stats collection,它会在维护窗口内对未分析对象做全表扫描式收集,极易与业务 SQL 冲突;执行SELECT client_name, status FROM dba_autotask_client确认状态,用DBMS_AUTO_TASK_ADMIN.DISABLE关停,改为业务低峰期手工收集 -
错误认证尝试:当
p3值解出 namespace = 79(ACCOUNT_STATUS),说明大量失败登录(ORA-1017)正在刷库缓存;查dba_audit_session中returncode != 0的记录,封禁异常 IP 或重置弱密码账户
真正难处理的不是锁本身,而是持有锁的会话往往不报错、不超时、也不释放——它可能卡在磁盘 I/O、网络响应或一个没 commit 的事务里。所以诊断时永远先问:这个会话最近执行了什么?有没有人刚跑完一个耗时 DDL?有没有人在用旧客户端反复连错密码?答案通常就藏在这些上下文里,而不是在参数调优中。











