Troubleshooting Library Cache: Lock, Pin and Load Lock (Doc ID 444560.1)
How to Find which Session is Holding a Particular Library Cache Lock (Doc ID 122793.1)
WAITEVENT: "library cache lock" Reference Note (Doc ID 34578.1)
一、基本原理
缓存在 library cache 中的对象我们称之为库缓存对象( library cache object ) , 所有的库缓存对象都是以库缓存对象句柄( library cache object handle )的结构存储在 library cache 中, oracle 通过访问库缓存对象句柄来访问库缓存对象。
(可以把 library cache 理解为一本书,而 SQL 语句的对象就是书中的页,而句柄就是目录,通过目录可以快速定位到指定内容的页。)
oracle 在访问库缓存对象时( library cache object ),需要先找到对应的 bucket , 然后获得 lock , 持有着 lock 去寻找该 bucket 下对应的 handles, 这个持有的过程就是 library cache lock 。在找到 handle 后,根据读取到的句柄中的信息去搜寻其他内存块地址时,此时持有 library cache pin, 直至操作完毕释放。 library cache lock 针对的是 handle , library cache pin 针对的是 heap 。
在访问库缓存对象时,比如软解析时,要从库缓存中读取执行计划。 Oracle 首先找到句柄,读取句柄中的信息,这就叫做一次库缓存 Get 。如果库缓存中不包括对象的句柄信息, Oracle 就要重新在库缓存中分配内存、构造句柄,这就是库缓存句柄未命中( Get Miss )。相反,如果在库缓存中找到了对象句柄,就是库缓存句柄命中( Get Hit )。硬解析时,就会发生 Get Miss 。而软解析则是 Get Hit 。在取出句柄中的其他内存块地址后,每访问一个内存块,都叫做一次库缓存 Pin 。如果相应的内存块已经不在内存中了,这就是 Pin Miss , Pin 的未命中。相反就是 Pin Hit 。
lock 主要有三种模式 : Null, share(2), Exclusive(3) 。在读取访问对象时 , 通常需要获取 Null( 空 ) 模式以及 share( 共享 ) 模式的锁定。在修改对象时 , 需要获得 Exclusive( 排他 ) 锁定。
pin 操作跟 lock 一样 , 也有三种模式 : Null, shared(2) 和 exclusive(3) 。只读模式时获得 shared pin, 修改模式获得 exclusive pin 。
模式为 shared(2) 的 pin 会阻塞任何 exclusive(3) 的 pin 请求。模式为 shared(3) 的 pin 也会阻塞任何 exclusive(2) 的 pin 请求。
所有的 DDL 都会对被处理的对象请求排他类型的 lock 和 pin 。
二、主要原因
sql 语句硬解析频繁或 version count 过高;
在繁忙事务期间执行 DDL 操作(比如统计信息收集动作、重新编译存储过程、包等);
NAME PARAMETER1 PARAMETER2 PARAMETER3 ------------------------- --------------- --------------- ---------------------------------------------------------------- library cache lock handle address lock address 100*mode+namespace
查找当前系统 library cache 中存在问题的sql 语句
SET linesize 120
COL operation format a55
COL cost format 99999
COL kbytes format 999999
COL object format a25
SELECT hash_value,
child_number,
LPAD(' ', 2 * DEPTH) || operation || ' ' || options ||
DECODE(ID, 0, SUBSTR(optimizer, 1, 6) || ' Cost=' || TO_CHAR(COST)) operation,
object_name OBJECT,
COST,
ROUND(BYTES / 1024) kbytes
FROM v$sql_plan
WHERE hash_value IN (SELECT a.sql_hash_value
FROM v$session a, v$session_wait b
WHERE a.SID = b.SID
AND b.event = '&waitevent')
ORDER BY hash_value, child_number, ID;
