library cache和dictionary cache

library cache最主要的功能就是存放用户提交的SQL语句、SQL语句相关的解析树(解析树也就是对SQL语句中所涉及的所有对象的展现)、执行计划、用户提交的PL/SQL程序块(包括匿名程序块、存储过程、包、函数等)以及它们转换后能够被Oracle执行的代码等。为了对这些内存结构进行管理,library cache中还存放了很多控制结构,包括lockpindependency table等。

library cache也存放了很多的数据库对象的信息,包括表、索引等。有关这些数据库对象的信息都是从dictionary cache中获得的。如果用户对library cache中的对象信息进行了修改,比如为表添加了一个列等,则这些修改会返回到dictionary cache中。

library cache中存放的所有信息单元都叫做对象(object),这些对象可以分成两类:一类叫存储对象,也就是上面所说的数据库对象。它们是通过显式的SQL语句或PL/SQL程序创建出来的,如果要删除它们,也必须通过显式的SQL命令进行删除。这类对象包括表、视图、索引、包、函数等;另一类叫做过渡对象,也就是上面所说的用户提交的SQL语句或者提交的PL/SQL匿名程序块等。这些过渡对象是在执行SQL语句或PL/SQL程序的过程中产生的,并缓存在内存里。如果实例关闭则删除,或者由于内存不足而被交换出去,从而被删除。

当用户提交SQL语句或PL/SQL程序块到shared pool以后,会在library cache中生成一个可执行的对象,这个对象就叫做游标(cursor)。不要把这里的游标与标准SQLANSI SQL)的游标混淆起来了,标准SQL里的游标是指返回多条记录的SQL形式,需要定义、打开、关闭。下面所说到的游标如无特别说明,都是指library cache中的可执行的对象。游标是可以被所有进程共享的,也就是说如果100个进程都执行相同的SQL语句,那么这100个进程都可以共用该SQL语句所产生的游标,从而节省了内存。

每个游标都是由library cache中的两个或多个对象所体现的,至少两个对象。一个对象叫做父游标(parent cursor),包含游标的名称以及其他独立于提交用户的信息。从v$sqlarea视图里看到的都是有关父游标的信息;另外一个或多个对象叫做子游标(child cursor),如果SQL文本相同,但是可能提交SQL语句的用户不同,或者用户提交的SQL语句所涉及的对象为同名词等,都有可能生成不同的子游标。因为这些SQL语句的文本虽然完全一样,但是上下文环境却不一样,因此这样的SQL语句不是一个可执行的对象,必须细化为多个子游标后才能够执行。子游标含有执行计划或者PL/SQL对象的程序代码块等。

在介绍library cache的内部管理机制前,先简单介绍一下所谓的hash算法。

Oracle内部在实现管理的过程中大量用到了hash算法。hash算法是为了能够进行快速查找定位所使用一种技术。所谓hash算法,就是根据要查找的值,对该值运用一定的hash函数后得出该值所在的索引号。进入索引号所对应的一列数值列表(可以理解为一个二维数组)里,然后再对其中所含有的值进行逐个比较,从而找到该值。这样就避免了对整个数值列表进行扫描才能找到该值,这种全扫描的方式显然要比hash查找方式低效很多。其中,每个索引号对应的数值列在Oracle里都叫做一个hash bucket

我们来列举一个最简单的hash算法。假设我们的数值列表最多可以有10个元素,也就是有10hash bucket,每个bucket最多可以包含10个数值。则对应的二维数组就是t[10][10]。我们可以定义hash算法为n MOD 10。通过这种算法,可以将所有进入的数据均匀放在10hash bucket里面,hash bucket编号从09。比如,我们把1100都通过这个hash函数均匀放到这10hash bucket里,当查找32在哪里时,只要将32 MOD 10等于2,这样就知道32必定位于2hash bucket里,于是到t[2][10]里去找,2hash bucket里有10个数值,逐个比较2hash bucket里是否存在32就可以了。这里可以看出,为了找到32这个值,我们总共需要比较11次(1+10)。如果不使用hash算法,而采用遍历扫描的方式,则需要比较100次。

library cache就是使用多个hash bucket来管理的,其hash算法当然比我们前面列举的要复杂多了。每个hash bucket后面都串连着多个句柄(该句柄叫做library cache object handle),这些句柄描述了library cache里的对象的一些属性,包括名称、标记、指向对象所处的内存地址的指针等。实际上,hash bucket就是通过串连起来的对象句柄才体现出来的,它本身是一个逻辑上的概念,是一个逻辑组,而不像对象是一个具体的实体。Oracle根据shared_pool_size所指定的shared pool尺寸自动计算hash buckets的个数,shared pool越大,则可以挂载的对象句柄就越多。
可以使用图5-3来描述library cache的结构。


当某个进程需要处理某个对象时,比如处理一条新进入的SQL语句时,它会对该SQL语句应用hash函数算法,以决定其所在的hash bucket的编号,然后进入该hash bucket进行扫描以确定是否存在相同的SQL语句。有可能会发生该对象的句柄存在,但是句柄所指向的对象已经被交换出内存的情况出现。这时对应的对象必须被再次装载(reload)。也可能该对象的句柄都不存在,也就是说该条SQL语句是第一次被执行,这时进程必须重新构建一个对象句柄挂到hash bucket上,然后再重新装载对象。SQL语句相关的对象有很多(最直观的就是SQL语句的文本),这些对象都存放在library cache里,它们都通过句柄来访问。可以把library cache理解为一本书,而SQL语句的对象就是书中的页,而句柄就是目录,通过目录可以快速定位到指定内容的页。当一条SQL语句进入library cache的时候,先将SQL文本转化为对应ASCII数值,然后对这些ASCII数值进行hash函数的运算,传入函数的参数包括SQL语句的名称(name,对于SQL语句来说其name就是SQL语句的文本)以及命名空间(namespace,对于SQL语句来说是“SQL AREA”,表示共享游标。可以从视图v$librarycache里找到所有的namespace)。运用hash函数后得到一个值,该值就是hash bucket的号码,从而该SQL语句被分配到该号的hash bucket里去。

对象句柄存放了对象的名称(name)、对象所属的命名空间(namespace)、有关对象的一些标记(比如对象是否为只读、为本地对象还是远程对象、是否被pin在内存中等)以及有关对象的一些统计信息等。其中存放的最重要的内容应该就是指向Heap 0对象的指针了。Heap 0用来存放与对象有直接关系的一些信息,比如对象类型、对象相关的表、实际的执行计划、执行PL/SQL的机器码等。Heap是由一个或多个chunk组成的,这些chunk可以是分散的分布在library cache中的,不需要连续分布。

我们可以通过查询视图v$db_object_cache来显示library cache中有哪些对象被缓存,以及这些对象的大小尺寸。比如,我们可以用下面的SQL语句来显示每个namespace中,大小尺寸排在前3名的对象:

select *
from (select row_number() over(partition by namespace
order by sharable_mem desc) size_rank,
namespace,
sharable_mem,
substr(name, 1, 50) name
from v$db_object_cache
order by sharable_mem desc)
where size_rank <= 3 
order by namespace, size_rank;

dictionary cache则是专门用来存放SYS schema所拥有的对象的内存区域。使用dictionary cache时以行为单位,而不像其他比如buffer cache以数据块为单位,因此dictionary cache也叫做row cache。构造dictionary cache的目的是为了加快解析SQL语句的速度,因为dictionary cache里存放了所有表的定义、Storage信息、用户权限信息、约束定义、回滚段信息、表的统计信息等。基本上我们不需要过多地关注它。

Oracle里是没有初始化参数来控制library cachedictionary cache应该占多大的内存的,我们只能控制shared pool的大小。因为前面说过,shared pool里的一个可用chunk,如果存放了数据字典的信息,那么它就属于dictionary cache。否则,如果存放了SQL文本或执行计划等信息,则它就属于library cache。有时某chunk原先可能放的是SQL文本,后来由于内存不足被数据字典信息所覆盖,则该chunk就从library cache变成了dictionary cache。所以我们不能单独控制library cachedictionary cache各是多大。

  • 22
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值