在日常运维中,“library cache”相关等待较为常见,主要分为“library cache lock”或“library cache pin”,前者维护“library object handle”上的并发访问,后者维护“library object handle”下对应heap的并发访问,lock管理并发,pin管理一致性。
当我们编译存储过程、函数或视图的时候,Oracle 就会在这些对象的handle 上获得一个“library cache lock ”,然后在这些对象的heap 上获得pin ,这样就能保证在编译的时候其他进程不会来更改这些对象。
有了以上的理论基础,当高峰期编译对象出现会话堵塞的问题时,我们应该如何处理呢? 这里主要会用到基表DBA_KGLLOCK ,其包含如下两个字段。
q kgllkuse 字段:“Address of the user session that holds the lock or pin ”,主要用于记录持有lock 或pin 的用户地址。
q kgllkhdl 字段:“Address of the handle for the KGL object ”,记录handle 对象地址。
故障发生时,首先查看后台等待事件,命令及输出具体如下:
SQL> select inst_id,sid, event, p1,p1text,p1raw,p2,p2text,p2raw from gv$session where wait_class<>'Idle';
INST_ID SID EVENT P1 P1TEXT P1RAW P2 P2TEXT P2RAW
------- ---- ------------------ ---------- ---------------- ---------------- ---------- ------------ ----------------
1 33 library cache pin 2081944584 handle address 000000007C17F408 2087901056 pin address 000000007C72D780
根据等待事件“library cache pin ”获取“p1 handle address 000000007C17F408 ”。
关联视图“dba_kgllock dk,v$session ”获取锁信息,命令及输出如下:
SQL> select s.sid,s.sql_id,s.event,dk.* from dba_kgllock dk,v$session s where s.saddr = dk.KGLLKUSE and KGLLKHDL='000000007C17F408';
SID SQL_ID EVENT KGLLKUSE KGLLKHDL KGLLKMOD KGLLKREQ KGLL
--- ------------- ------------------ ---------------- ---------------- -------- -------- ----
33 087rrdjwc2act library cache pin 00000000A92FC040 000000007C17F408 3 0 Lock
33 087rrdjwc2act library cache pin 00000000A92FC040 000000007C17F408 0 3 Pin
从以上返回结果中可以看出,我们并没有找到pin 的持有者,KGLLKREQ 表示当前会话需要申请的锁模式,KGLLKMOD 表示当前系统中持有的锁模式,由于该系统为RAC ,各节点之间内存结构不同,handle address 不能公用,因此我们需要定位出owner 和object_name 在其他节点持有pin 的会话。命令及输出如下:
SQL> select ADDR,INDX,INST_ID,KGLHDADR,KGLNAOWN,KGLNAOBJ from x$kglob where KGLHDADR='000000007C17F408';
ADDR INDX INST_ID KGLHDADR KGLNAOWN KGLNAOBJ
---------------- ---- ------- ---------------- ---------- ---------
00007FE9B0B45850 4979 1 000000007C17F408 SYS DUMMY
其中,x$kglob 为“library cache object ”对象的视图。
RAC 2 节点根据object_name 查找对应的handle address 信息,命令及输出如下:
SQL> select ADDR,INDX,INST_ID,KGLHDADR,KGLNAOWN,KGLNAOBJ from x$kglob where KGLNAOBJ='DUMMY'
ADDR INDX INST_ID KGLHDADR KGLNAOWN KGLNAOBJ
---------------- ---- ------- ---------------- --------- ---------
00007F987B1D8ED0 4150 2 00000000AA193870 SYS DUMMY
查看锁的持有情况,命令及输出如下:
SQL> select s.sid,s.sql_id,s.event,dk.* from dba_kgllock dk,v$session s where s.saddr = dk.KGLLKUSE and KGLLKHDL='00000000AA193870';
SID SQL_ID EVENT KGLLKUSE KGLLKHDL KGLLKMOD KGLLKREQ KGLL
--- ------------- ----------------- ---------------- ---------------- -------- -------- ----
424 d4wnj5j8y1mq7 PL/SQL lock timer 00000000A9787DA0 00000000AA193870 1 0 Lock
424 d4wnj5j8y1mq7 PL/SQL lock timer 00000000A9787DA0 00000000AA193870 2 0 Pin
最终定位 2 上的会话424 其持有模式为2 (即共享模式)的锁,堵塞了KGLLKREQ 3 排它锁的申请,为了能够顺利编译,我们只需要杀掉节点2 上的会话424 即可。
像“1 节点”“2 节点”“3 节点”,是否可以改为“节点1 ”“节点2 ”“节点3 ”?
