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操作(比如统计信息收集动作、重新编译存储过程、包等);
sql
NAME PARAMETER1 PARAMETER2 PARAMETER3
------------------------- --------------- --------------- ----------------------------------------------------------------
library cache lock handle address lock address 100*mode+namespace
查找当前系统 library cache 中存在问题的sql语句
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;