Library Cache是Shared pool的一部分,主要存放Shared cursor(SQL)和PLSQL对象(function,procedure,trigger)的信息。以及这些对象所依赖的table,index,view等对象信息。

Library cache需要解决三个问题:

  1. 快速定位的问题:Library cache中对象众多,Oracle如何管理这些对象,以便服务进程可以迅速找到他们需要的信息。比如某个服务进程需要迅速定位某个SQL是否存在于Library cache中。

  2. 关系依赖的问题:Library cache中的对象存在复杂的依赖关系,当某个objec失效时,可以迅速将依赖其的对象也置为失效状态。比如某个表发生了结构变化,依赖其的SQL语句需要重新解析。

  3. 并发控制的问题:Library cache中必须有一个并发控制的机构,比如锁机制,来管理大量共享对象的并发访问和修改的问题,比如某个SQL在重新编译的同时,其所依赖的对象不能被修改。

 

Library Cache结构:

Oracle 利用hash table结构来解决Library cache中快速定位的问题,hash table是由很多hash bucket组成的数组:

 

其中原理与Buffer Cache中定位Block方式相同,将对象信息的hash定位至某个hash bucket中,然后顺序扫描Bucket中的List,实现快速定位对象的目的。

Library Cache Handle是对象指针,指针的namespace属性表示其指向的对象类型:比如CRSR(Cursor),TABL(Table),INDX(Index) ,PROD(Procedure),TRIG(Trigger)等。

LCO(Library cache object)是handle指向的对象,LCO包含以下几个部分:

 

1. Object Types

Object 是一组根据对象所属类型定义的命名空间组

每个Object只能是一种类型

所有相同类型的Object属于相同的命名空间

一个命名空间可能用于两个以上的相同类型

最重要的命名空间成为游标(CRSR)用于存放共享的SQL游标。

 

Library cache object的type,包括:shared,cursor,index,table,cluster,view,synonym,sequence,procedure,function,package,table body,package,body,trigger等等。

 

2. Object Names

LCO名称有三个部分:Schema名,Object名,DB Link名(仅远程对象)

格式:SCHEMA.NAME@DBLINK

 

3. Object Flags

1) Public Flags

不受pins或latches的保护

包含对象的类型细节

 

2) Status Flags

受pins的保护

表明对象是否被created/dropped/altered/updated

 

3) Special status flags

受 latch的保护

 与Object的有效性和权限相关

 

 

4. Object Tables

1) Dependency table

      指向对象依赖的表,比如:select * from table这个cursor对象,依赖table这个表。这里指向table这个表handle

 

2) Child table

      指向对象的子对象,比如某个Cursor的Child Cursor,Child Cursor是指SQL文本相同,但是SQL实际含义不同,如执行用户、环境、计划不同等。我们一般称为SQL的不同版本。一个SQL至少包含一对父子游标。

 

3) Transaltion table

 

4) Authorization table

       对象的授权信息。

5) Access table

 

6) Read-only dependency table

 

7) Schema name table

 

5.Data blocks

     data block是一个指针,指向了data heap,即存放真实数据的地方,主要包括:diana tree, p-code, source code, shared cursor context area等等,其中SQL执行计划就存放在Heap 6:SQL Context中。如下:

Library cache对象依赖关系:

    对象依赖关系是利用LCO中的Dependency table来完成的,通过以下情况说明对象依赖:

两个共享游标:

SQL1:select * from emp

SQL2:select * from emp和select a.name from emp a,dept b where a.dept_id=b.id and b.name=:1;

 

       SQL1产生了两个子游标,也就是SQL文本相同的两个不同版本,他们同时依赖emp表。SQL2只有一个版本,因为每个游标最少有一个子游标,所以它只有一个子游标,并且同时依赖dept表和emp表。

我这里做个尝试DUMP Library Cache的信息

SQL> alter session set events'immediate trace name library_cache cancel';

SQL> select * from dual  //这里我执行一个查询DUAL的语句。观察在Library Cache中都做了什么。

SQL> alter session set events'immediate trace name library_cache off';

SQL> select value from v$diag_info;

 

Library Cache库缓存_第1张图片可以看该语句位于Library Cache中的第108289个Bucket中。对应的LibraryHandle指针的地址与v$sqlarea中的ADDRESS一致:

SELECT SQL_ID,
       ADDRESS,
       HASH_VALUE,
       EXECUTIONS,
       LOADS,
       PARSE_CALLS,
       INVALIDATIONS,
       SQL_TEXT,
       CHILD_ADDRESS,
       SQLTYPE
  FROM V$SQL
 WHERE SQL_TEXT = 'select * from dual';

wKiom1ZOmiPgdLDQAAAXe3XRgJk669.png

 

Hash部分也是一致的
SQL> select to_number('382da701','xxxxxxxxx') from dual;

TO_NUMBER('382DA701','XXXXXXXXX')
---------------------------------
                        942515969

在Library Cache对于SQL执行的记录部分,关注以下块内容

ObjectName:记录了SQL对象语句。

WaitersLists:

LibraryObject:记录Library对象地址。

NamespaceDump:记录SQL的ID值、父游标的地址和最大子游标数。

 

Library cache中的并发控制

        Oracle利用Library cache lock和Library cache pin来实现并发控制,Library cache lock是在handle上获取的,而Library cache pin则是在data heap上获取。访问对象时,首先必须获取handle上的lock,然后将访问的数据pin在内存中。lock的作用是控制进程间的并发访问,而pin的作用是保证数据一致性,防止数据在访问时被交换出去。

 

Library cache lock有三种模式:null,share,exclusive,Library cache pin有两种模式:share,exclusive。下面详细解释在修改和访问对象时,lock和pin的作用:

 

修改对象

        编译SQL或PLSQL对象,获取该对象(cursor,procedure)handle上exclusive类型的lock,并且持有data heap上exclusive类型的pin,防止其他人读取和修改。同时,在该对象所依赖的对象(table)上,必须持有一个share类型的lock和pin,防止在修改的过程中,被其他进程所修改。

 

访问对象

        访问SQL或PLSQL对象,获取该对象(cursor,procedure)handle上NULL类型的lock,并且持有data heap上share类型的pin,同时,在其依赖的对象(table)上持有share类型的lock和pin。如果一个procedure依赖另外一个function,那么在被依赖的function上,也需要持有share类型的lock和pin。

NULL类型的lock比较特殊,它只存在于cursor和procedure等只读对象上,它并不起到任何并发控制的作用,它更象是一个trigger,当对象失效时,通知所有访问这个cursor的进程。比如:select * from emp这个SQL,依赖emp表,当emp表发生变化时,cursor上的NULL lock被打破,所有有访问这个cursor的进程都会知道该对象已经失效。

当持有对象的library cache pin时,会在row cache中对相应的对象加锁,就是row cache lock,阻止可能导致数据字典信息混乱的DDL发生。

lock和pin的实现类似于enqueue,在每个handle上都有lock和pin的holder list和waiter list,用来保存持有该资源和等待该资源的队列。

 

阻塞分析

现实情况中,我们有一个数据库中存在被应用大量频繁访问的procedure,当依赖的表发生变更时,导致该procedure失效,这时会出现大量的library cache lock和library cache pin的等待,堵塞应用访问,造成了重大故障。出现这个问题的原因是:当procedure失效后,所有访问该对象的进程都尝试去编译,大量进程尝试获取exclusive类型的lock和pin,出现了大量的等待。后续的Oracle版本作出了改进,当出现这种情况时,只允许第一个进程尝试去编译该对象,编译通过后,所有的进程就可以并发访问,避免了大量进程同时尝试编译的情况出现。

 

Library cache中的Latch:

Library cache中相关的latch包括:shared pool latch,library cahce latch,library cache lock latch,library cache pin latch。

Share pool latch的主要作用是分配或释放空间时使用,从Oracle9i开始,sharedpool被分成了很多个subpool,由多个shared pool latch保护,Oracle开始支持更大的shared pool。

Library cache latch的主要作用是在hash bucket中定位handle时使用,library cache lock latch和library cache pin latch分别是获取lock和pin时,需要取得的latch。

shared pool大小不合理,大量的硬解析以及SQL版本过多都可能导致shared pool latch和library cache latch的争用。

从Oracle10g开始,Oracle正在逐步用mutex取代library cache中的latch,cursor:pin S和cursor:pin X相当于share和exclusive类型的library cache pin,cursor:pin S wait on X则表示share方式正在等待exclusive锁定。