浅析Oracle中的Library Cache Lock和Library Cache Pin等待事件

在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项数据库领域的发明专利。

你可能感兴趣的:(浅析Oracle中的Library Cache Lock和Library Cache Pin等待事件)