在Oracle数据库中,如果运行一个SQL语句或者Stored Procedure,首先需要将它们加载到Shared Pool的Library Cache中,而这些对象也称之为Library Cache Object。
执行或者修改这些Library Cache Object时,会经历以下阶段。拿一个存储过程来举例说明,我们先来看执行时的情况:
1、首先,这个LibraryCache Object会获得一个Library Cache Lock,这个锁的mode=1,也就是NULL锁。如下:
ADDR KGLLKHDL KGLLKMOD KGLLKREQ KGLLKFLG
---------------- ---------------- -------------------- ----------
00002B4BD2F556F8 000000012FFD6F20 1 0 2
2、在获得了Library Cache Lock之后,这个对象会尝试获得Library Cache Pin。因为是执行,所以mode=2,也就是Row Share锁。如下:
ADDR KGLPNHDL KGLPNMOD KGLPNREQ KGLPNFLG
---------------- ---------------- -------------------- ----------
00002B4BD2F55D30 000000012FFD6F20 2 0 8
3、执行后,这个对象上的Library Cache Bin会释放。
12:00:19 SQL> select addr, kglpnhdl, kglpnmod,kglpnreq, kglpnflg from x$kglpn where kglpnhdl = '000000012FFD6F20';
no rows selected
Elapsed: 00:00:00.04
4、因为Library Cache Lock是一种DDL锁,是Parse锁,维持着对象间的依赖关系,所以执行后仍然存在。只不过x$kgllk
上的kgllkflg
被reset为0。
ADDR KGLLKHDL KGLLKMOD KGLLKREQ KGLLKFLG
---------------- ---------------- -------------------- ----------
00002B4BD2F555A0 000000012FFD6F20 1 0 0
以上是执行一个Library Cache Object的过程。如果要对一个Library Cache Object进行修改,过程是类似的,但获取锁的模式会有不同。因为较难单独模拟,这里就不给出例子,只是做过程说明,后面会和执行的情况一起来模拟锁等待的情况。
1、首先还是要获得Library Cache Lock,但修改时获得的是mode=3的锁,而不是mode=1。mode=3是Row Exclusive锁,这个模式和mode=1是兼容的,后面我们会举例说明;
2、获得Library Cache Lock之后,会继续获取Library Cache Pin。由于是修改,也需要获取mode=3的锁;
3、在修改后,会释放Library Cache Pin;
4、释放Library Cache Pin后,也会释放Library Cache Lock;
知道了执行和修改Library Cache Object时锁的获取次序和模式后,我们就来看一下如果两种情况并发出现时系统看到的等待情况。为了更好地模拟生产实际情况,我们先执行一个Stored Procedure,然后在另外一个session对它尝试compile,紧接着第3个session再尝试执行该Stored Procedure。
三个session的SID分别为218,26,937,对应上面提到的第1、2、3个session。
session: 218
17:50:17 SQL> exec test_kgllk;
PL/SQL procedure successfully completed.
Elapsed: 00:01:00.01
17:52:16 SQL>
session: 26
17:50:57 SQL> alter procedure test_kgllkcompile;
Procedure altered.
Elapsed: 00:00:57.41
17:52:16 SQL>
session: 937
17:50:57 SQL> exec test_kgllk;
PL/SQL procedure successfully completed.
Elapsed: 00:01:54.53
17:53:16 SQL>
执行后锁等待的状态:
17:50:07 SQL> select sid, kglpnhdl, kglpnmod,kglpnreq, kglpnflg
from17:51:33 2 x$kglpn p, v$session s
where kglpnhdl = '000000012FFD6F20'17:51:33 3
and s.saddr = p.kglpnses;17:51:33 4
select sid, kgllkhdl, kgllkmod, kgllkreq,kgllkflg
SIDKGLPNHDL KGLPNMOD KGLPNREQ KGLPNFLG
---------- ---------------- ---------- --------------------
937000000012FFD6F20 0 2 0
26000000012FFD6F20 0 3 4096
218000000012FFD6F20 2 0 8
Elapsed: 00:00:00.04
17:51:33 SQL> 17:51:33 SQL>
17:51:33 2 from x$kgllk k, v$session s
17:51:33 3 where kgllkhdl ='000000012FFD6F20'
17:51:33 4 and s.saddr = k.kgllkses;
SIDKGLLKHDL KGLLKMOD KGLLKREQ KGLLKFLG
---------- ---------------- ---------- --------------------
218000000012FFD6F20 1 0 2
937000000012FFD6F20 1 0 2
26000000012FFD6F20 3 0 1
Elapsed: 00:00:00.04
17:51:34 SQL> 17:51:34 SQL> select sid,serial#, event, p1, p1raw, p2, p2raw, p3, p3raw
17:51:34 2 from v$session
17:51:34 3 where wait_class# !=6;
SID SERIAL# EVENT P1 P1RAW P2 P2RAW P3 P3RAW
---------- ---------- ------------------------------ ---------------- ---------- ---------------- --------------------------
26 40202 library cache pin 5100105504 000000012FFD6F20 539138467200000001415A0060 3.4456E+14 0001395F00010003
937 21896 library cache pin 5100105504 000000012FFD6F20 545964661600000001456B9898 3.4456E+14 0001395F00010002
Elapsed: 00:00:00.00
17:51:35 SQL>
按照前面分析的Library Cache Object执行或者修改时需要获得锁的次序和模式,我们来分析一下:
1、在session218执行了test_kgllk后,它获得了mode=1的Library Cache Lock以及mode=2的Library Cache Pin;
2、session26需要重新编译test_kgllk
,它首先需要获得mode=3的Library Cache Lock,但是mode 3和mode 1是兼容的,所以并没有阻塞在Library Cache Lock上;
3、session26继续申请mode 3的Library Cache Pin,但是发现Library Cache Pin已经被session218持有在了mode 2,而两种模式不兼容,所以出现了session 26需要等待Library Cache Pin;
4、session937需要执行test_kgllk
,首先需要获得mode 1的Library Cache Lock,尽管被session26持有了mode 3,但因为两种模式兼容,所以session 937也顺利持有了Library Cache Lock;
5、session937还需要获得mode 2的Library Cache Pin,但session26已经在申请mode 3的Library Cache Pin,模式不兼容,必须等待。因此session 937开始等待Library Cache Pin;
可见,我们看到的结果和预期是完全一致的。
但情况也并不总是如此,我发现有时session 937会被阻塞在Library Cache Lock上。如下所示:
session 218:
17:59:59 SQL> exec test_kgllk;
PL/SQL procedure successfully completed.
Elapsed: 00:01:00.01
18:03:24 SQL>
session 26:
17:59:59 SQL> alter procedure test_kgllkcompile;
Procedure altered.
Elapsed: 00:00:59.06
18:03:24 SQL>
session 937:
18:02:11 SQL> exec test_kgllk;
PL/SQL procedure successfully completed.
Elapsed: 00:01:57.91
18:04:24 SQL>
执行后的锁等待的状态如下:
18:00:53 SQL> select sid, kglpnhdl, kglpnmod,kglpnreq, kglpnflg
from x$kglpn p, v$session s
where kglpnhdl = '000000012FFD6F20'18:02:32 2 18:02:32 3
and s.saddr = p.kglpnses;18:02:32 4
select sid, kgllkhdl, kgllkmod, kgllkreq,kgllkflg
from x$kgllk k, v$session s
SIDKGLPNHDL KGLPNMOD KGLPNREQ KGLPNFLG
---------- ---------------- ---------- --------------------
26000000012FFD6F20 0 3 4096
218000000012FFD6F20 2 0 8
Elapsed: 00:00:00.04
18:02:32 SQL> 18:02:32 SQL> 18:02:32 2
18:02:32 3 where kgllkhdl ='000000012FFD6F20'
and s.saddr = k.kgllkses;18:02:32 4
SIDKGLLKHDL KGLLKMOD KGLLKREQ KGLLKFLG
---------- ---------------- ---------- --------------------
937000000012FFD6F20 0 2 0
218000000012FFD6F20 1 0 2
26000000012FFD6F20 3 0 1
Elapsed: 00:00:00.03
18:02:32 SQL> 18:02:32 SQL> select sid,serial#, event, p1, p1raw, p2, p2raw, p3, p3raw
from v$session18:02:32 2
18:02:32 3 where wait_class# !=6;
SID SERIAL# EVENT P1 P1RAW P2 P2RAW P3 P3RAW
---------- ---------- ------------------------------ ---------------- ---------- ---------------- --------------------------
26 40202 library cache pin 5100105504 000000012FFD6F20 5294013936000000013B8C3DF0 3.4456E+14 0001395F00010003
937 19587 library cache lock 5100105504 000000012FFD6F20 545964634400000001456B9788 3.4456E+14 0001395F00010002
Elapsed: 00:00:00.00
18:02:33 SQL>
可以看到,在x$kgllk
中,session 937试图获取mode2的Library Cache Lock,而并不是mode=1的NULL。因为session26已经获取了mode 3的Library Cache Lock,两种模式不兼容,所以session 937开始等待Library Cache Lock。也正因为被阻塞在Library Cache Lock,所以session 937也无法继续下面的步骤去获取Library Cache Pin,因此在x$kglpn
中我们看不到这样一条记录。
我分别在11gR2,12.1.0.1和12.1.0.2上进行了测试。在11gR2和12.1.0.1两种现象是严格交替出现的,也就是说,一次可以看到两条Library Cache Pin的等待,另一次可以看到Library Cache Lock和Library Cache Pin的等待。而在12.1.0.2上似乎没有交替出现的规律,多数情况下都是两个Library Cache Pin的等待,有时会看到Library Cache Lock和Library Cache Pin的等待。
来源:沃趣科技(woqutech)
作者:汪洋,中国平安集团旗下平安科技数据库技术部总监。从1994年开始接触Oracle 6数据库,于1998年获取Oracle 7.3 OCP证书,迄今已从事Oracle相关开发运维工作20年。在加入平安之前,就职于Oracle香港高级客户服务部门,为中国、香港以及澳门客户提供数据库架构设计,数据库性能优化等高级服务。加入平安后,负责数据库技术引入,数据库产品选型,数据库架构设计,数据库规范制定,开发、测试、生产环境运维等工作。个人拥有5项数据库领域的发明专利。