计算机软件及应用19-Shared pool深入分析及性能调整_第1页
计算机软件及应用19-Shared pool深入分析及性能调整_第2页
计算机软件及应用19-Shared pool深入分析及性能调整_第3页
计算机软件及应用19-Shared pool深入分析及性能调整_第4页
计算机软件及应用19-Shared pool深入分析及性能调整_第5页
已阅读5页,还剩95页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

sharedpool的概念用户提交的命令:解析、执行用户命令的解析:解析的过程是一个相当复杂的过程,它要考虑各种可能的异常情况,比方SQL语句涉及到的对象不存在、提交的用户没有权限等等。而且,还需要考虑如何执行SQL语句,采用什么方式去获取数据等。解析的最终结果是要产生oracle自己内部的执行方案,从而指导SQL的执行过程。可以看到,解析的过程是一个非常消耗资源的过程。因此,oracle在解析用户提交的SQL语句的过程中,如果对每次出现的新的SQL语句,都按照标准过程完整的从头到尾解析一遍的话,效率太低,尤其随着并发用户数量的增加、数据量的增加,数据库的整体性能将直线下降。

SQL语句静态局部和动态局部oracle对SQL语句进行了概括和抽象,将SQL语句提炼为两局部,一局部是SQL语句的静态局部,也就是SQL语句本身的关键词、所涉及的表名称以及表的列等。另一局部就是SQL语句的动态局部,也就是SQL语句中的值〔即表里的数据〕。很明显的,整个数据库中所包含的对象数量是有限的,而其中所包含的数据那么是无限的。而正是这无限的数据导致了SQL语句的千变万化,也就是说在数据库运行的过程中,发生的所有SQL语句中,静态局部可以认为数量是有限的,而动态局部那么是无限的。而实际上,动态局部对解析的影响相比静态局部对解析的影响来说是微乎其微,也就是说通常情况下,对于相同的静态局部的SQL语句来说,不同的动态局部所产生的解析结果〔执行方案〕根本都是一样的。这也就为oracle提高解析SQL语句的效率提供了方向。

共享池oracle会将用户提交来的SQL语句都缓存在内存中。每次处理新的一条SQL语句时,都会先在内存中查看是否有相同的SQL语句。如果相同那么可以减少最重要的解析工作〔也就是生成执行方案〕,从而节省了大量的资源;反之,如果没有找到相同的SQL语句,那么必须重新从头到尾进行完整的解析过程。这局部存放SQL语句的内存就叫做共享池〔sharedpool〕。当然,sharedpool里不仅仅是SQL语句,还包括管理sharedpool的内存结构以及执行方案、控制信息等等内存结构。

绑定变量当oracle在sharedpool中查找相同的SQL语句的过程中,如果SQL语句使用了绑定变量〔bindvariable〕,那么就是比较SQL语句的静态局部,前面我们已经知道,静态局部是有限的,很容易就能够缓存在内存里,从而找到相同的SQL语句的概率很高。如果没有使用绑定变量,那么就是比较SQL语句的静态局部和动态局部,而动态局部的变化是无限的,因此这样的SQL语句很难被缓存在sharedpool里。毕竟内存是有限的,不可能把所有的动态局部都缓存在sharedpool里,即便能够缓存,管理这样一个无限大的sharedpool也是不可能完成的任务。不使用绑定变量导致的直接结果就是,找到相同的SQL语句的概率很低,导致必须完整的解析SQL语句,也就导致消耗更多的资源。从这里也可以看出,只有我们使用了绑定变量,才真正遵循了oracle引入sharedpool的哲学思想,才能够更有效的利用sharedpool共享池:库缓存+字典缓存sharedpool的大小由初始化参数shared_pool_size决定。10g以后可以不用设定该参数,而只需要指定sga_target,从而oracle将自动决定sharedpool的大小尺寸。在一个很高的层次上来看,sharedpool可以分为库缓存〔librarycache〕和数据字典缓存〔dictionarycache〕。Librarycache存放了最近执行的SQL语句、存储过程、函数、解析树以及执行方案等。而dictionarycache那么存放了在执行SQL语句过程中,所参照的数据字典的信息,包括SQL语句所涉及的表名、表的列、权限信息等。dictionarycache也叫做rowcache,因为这里面的信息都是以数据行的形式存放的,而不是以数据块的形式存放的。对于dictionarycache来说,oracle倾向于将它们一直缓存在sharedpool里,不会将它们交换出内存,因此我们不用对它们进行过多的关注。而librarycache那么是sharedpool里最重要的局部,也是在sharedpool中进进出出最活泼的局部,需要我们仔细研究。所以,我们在说到sharedpool实际上就可以认为是在指librarycache。sharedpool的内存结构〔逻辑结构〕从一个逻辑层面来看,sharedpool由librarycache和dictionarycache组成。sharedpool中组件之间的关系可以用以下图一来表示。从下面这个图中可以看到,当SQL语句〔selectobject_id,object_namefromsharedpool_test〕进入librarycache时,oracle会到dictionarycache中去找与sharedpool_test表有关的数据字典信息,比方表名、表的列等,以及用户权限等信息。如果发现dictionarycache中没有这些信息,那么会将system表空间里的数据字典信息调入buffercache内存,读取内存数据块里的数据字典内容,然后将这些读取出来的数据字典内容按照行的形式放入dictionarycache里,从而构造出dc_tables之类的对象。然后,再从dictionarycache中的行数据中取出有关的列信息放入librarycache中。

sharedpool的内存结构〔物理结构〕从一个物理的层面来看,sharedpool是由许多内存块组成,这些内存块通常称为chunk。Chunk是sharedpool中内存分配的最小单位,一个chunk中的所有内存都是连续的。这些chunk可以分为四类,这四类可以从x$ksmsp〔该视图中的每个行都表示sharedpool里的一个chunk〕的ksmchcls字段看到:

1)free:这种类型的chunk不包含有效的对象,可以不受限制的被分配。

2)recr:意味着recreatable,这种类型的chunks里包含的对象可以在需要的时候被临时移走,并且在需要的时候重新创立。比方对于很多有关共享SQL语句的chunks就是recreatable的。

3)freeabl:这种类型的chunks包含的对象都是曾经被session使用过的,并且随后会被完全或局部释放的。这种类型的chunks不能临时从内存移走,因为它们是在处理过程中间产生的,如果移走的话就无法被重建。

4)perm:意味着permanent,这种类型的chunks包含永久的对象,大型的permanent类型的chunks也可能含有可用空间,这局部可用空间可以在需要的时候释放回sharedpool里。

当chunk属于free类型的时候,它既不属于librarycache,也不属于dictionarycache。如果该chunk被用于存放SQL游标时,那么该chunk进入librarycache;同样,如果该chunk被用于存放数据字典的信息时,那么该chunk进入dictionarycache。

在sharedpool里,可用的chunk〔free类型〕会被串起来成为可用链表〔freelists〕或者也可以叫做buckets〔一个可用链表也就是一个bucket〕。我们可以使用下面的命令将sharedpool的内容转储出来看看这些bucket。

altersessionsetevents'immediatetracenameheapdumplevel2';

然后翻开产生的转储文件,找到“FREELISTS〞局部,可以发现类似如以下图所示的内容。每个bucket上挂的chunk的尺寸是不一样的,有一个递增的趋势。我们可以看到,每个bucket都有一个size字段,这个size就说明了该bucket上所能链接的可用chunk的大小尺寸。当一个进程需要sharedpool里的一个chunk时,假设当前需要21个单位的空间,那么该进程首先到符合所需空间大小的bucket〔这里就是bucket2〕上去扫描,以找到一个尺寸最适宜的chunk,扫描持续到bucket的最末端,直到找到完全符合尺寸的chunk为止。如果找到的chunk的尺寸比需要的尺寸要大,那么该chunk就会被拆分成两个chunk,一个chunk被用来存放数据,而另外一个那么成为free类型的chunk,并被挂到当前该bucket上,也就是bucket2上。然而,如果该bucket上不含有任何需要尺寸的chunk,那么就从下一个非空的bucket上〔这里就是bucket3〕获得一个最小的chunk。如果在剩下的所有bucket上都找不到可用的chunk,那么需要扫描已经使用的recreatable类型的chunk链表,从该链表上释放一局部的chunk出来,因为只有recreatable类型的chunk才是可以被临时移出内存的。当某个chunk正在被使用时〔可能是用户正在使用,也可能是使用了dbms_shared_pool包将对象钉在sharedpool里〕,该chunk是不能被移出内存的。比方某个SQL语句正在执行,那么该SQL语句所对应的游标对象是不能被移出内存的,该SQL语句所引用的表、索引等对象所占用的chunk也是不能被移出内存的。当sharedpool中无法找到足够大小的所需内存时,报ORA-4031错。当出现4031错的时候,你查询v$sgastat里可用的sharedpool空间时,可能会发现name为“freememory〞的可用内存还足够大,但是为何还是会报4031错呢?事实上,在oracle发出4031错之前,已经释放了不少recreatable类型的chunk了,因此会产生不少可用内存。但是这些可用chunk中,没有一个chunk是能够以连续的物理内存提供所需要的内存空间的,从而才会发出4031的错。对bucket的扫描、管理、分配chunk等这些操作都是在sharedpoollatch的保护下进行的。如果sharedpool含有数量巨大的非常小的free类型的chunk的话,那么扫描bucket时,sharedpoollatch会被锁定很长的时间,这也是8i以前的sharedpoollatch争用的主要原因。而如果增加sharedpool尺寸的话,仅仅是延缓sharedpoollatch的争用,而到最后,就会因为小的freechunks的数量越来越多,争用也会越来越严重。而到了9i以后,由于大大增加了可用chunk链表〔也就是bucket〕的数量,同时,每个bucket所管理的可用chunk的尺寸递增的幅度非常小,于是就可以有效的将可用的chunk都均匀的分布在所有的bucket上。这样的结果就是每个bucket上所挂的free类型的chunk都不多,所以在查找可用chunk而持有sharedpoollatch的时间也可以缩短很多。对于非常大的对象,oracle会为它们单独从保存区域里分配空间,而不是从这个可用chunk链表中来分配空间。这局部空间的大小尺寸就是由初始化参数shared_pool_reserved_size决定的,缺省为shared_pool_size的5%,这块保存区域与正常的chunk的管理是完全分开的,小的chunk不会进入这块保存区域,而这块保存区域的可用chunk也不会挂在bucket上。这块保存区域的使用情况可以从视图v$shared_pool_reserved中看到,通常来说,该视图的request_misses字段显示了需要从保存区域的可用链表上上获得大的chunk而不能获得的次数,该字段应该尽量为0。librarycache最主要的功能就是存放用户提交的SQL语句、SQL语句相关的解析树〔解析树也就是对SQL语句中所涉及到的所有对象的展现〕、执行方案、用户提交的PL/SQL程序块〔包括匿名程序块、存储过程、包、函数等〕以及它们转换后能够被oracle执行的代码等。为了对这些内存结构进行管理,还存放了很多控制结构,包括lock、pin、dependencytable等。

librarycache还存放了很多的数据库对象的信息,包括表、索引等等。有关这些数据库对象的信息都是从dictionarycache中获得的。如果用户对librarycache中的对象信息进行了修改,那么这些修改会返回到dictionarycache中。在librarycache中存放的所有的信息单元都叫做对象〔object〕,这些对象可以分成两类:一类叫存储对象,也就是上面所说的数据库对象。它们是通过显式的SQL语句或PL/SQL程序创立出来的,如果要删除它们,也必须通过显示的SQL命令进行删除。这类对象包括表、视图、索引、包、函数等等;另一类叫做过渡对象,也就是上面所说的用户提交的SQL语句或者提交的PL/SQL程序块等。这些过渡对象是在执行SQL语句或PL/SQL程序的过程中产生的,并缓存在内存里。如果实例关闭那么删除,或者由于内存缺乏而被交换出去,从而被删除。

父子游标当用户提交SQL语句或PL/SQL程序块到oracle的sharedpool以后,在librarycache中生成的一个可执行的对象,这个对象就叫做游标〔cursor〕。不要把这里的游标与标准SQL〔ANSISQL〕的游标混淆起来了,标准SQL的游标是指返回多条记录的SQL形式,需要定义、翻开、关闭。下面所说到的游标如无特别说明,都是指librarycache中的可执行的对象。游标是可以被所有进程共享的,也就是说如果100个进程都执行相同的SQL语句,那么这100个进程都可以同时使用该SQL语句所产生的游标,从而节省了内存。每个游标都是由librarycache中的两个或多个对象所表达的,至少两个对象。一个对象叫做父游标〔parentcursor〕,包含游标的名称以及其他独立于提交用户的信息。从v$sqlarea视图里看到的都是有关父游标的信息;另外一个或多个对象叫做子游标〔childcursors〕,如果SQL文本相同,但是可能提交SQL语句的用户不同,或者用户提交的SQL语句所涉及到的对象为同名词等,都有可能生成不同的子游标。因为这些SQL语句的文本虽然完全一样,但是上下文环境却不一样,因此这样的SQL语句不是一个可执行的对象,必须细化为多个子游标后才能够执行。子游标含有执行方案或者PL/SQL对象的程序代码块等。HASH算法在介绍librarycache的内部管理机制前,先简单介绍一下所谓的hash算法。

oracle内部在实现管理的过程中大量用到了hash算法。hash算法是为了能够进行快速查找定位所使用一种技术。所谓hash算法,就是根据要查找的值,对该值进行一定的hash算法后得出该值所在的索引号,然后进入到该值应该存在的一列数值列表〔可以理解为一个二维数组〕里,通过该索引号去找它应该属于哪一个列表。然后再进入所确定的列表里,对其中所含有的值,进行一个一个的比较,从而找到该值。这样就防止了对整个数值列表进行扫描才能找到该值,这种全扫描的方式显然要比hash查找方式低效很多。其中,每个索引号对应的数值列在oracle里都叫做一个hashbucket。我们来列举一个最简单的hash算法。假设我们的数值列表最多可以有10个元素,也就是有10个hashbuckets,每个元素最多可以包含20个数值。那么对应的二维数组就是t[10][20]。我们可以定义hash算法为nMOD10。通过这种算法,可以将所有进入的数据均匀放在10个hashbucket里面,hashbucket编号从0到9。比方,我们把1到100都通过这个hash函数均匀放到这10个hashbucket里,当查找32在哪里时,只要将32MOD10等于2,这样就知道可以到2号hashbucket里去找,也就是到t[2][20]里去找,2号hashbucket里有10个数值,逐个比较2号hashbucket里是否存在32就可以了。

librarycache就是使用多个hashbucket来管理的,其hash算法当然比我们前面列举的要复杂多了。每个hashbucket后面都串连着多个句柄〔该句柄叫做librarycacheobjecthandle〕,这些句柄描述了librarycache里的对象的一些属性,包括名称、标记、指向对象所处的内存地址的指针等。可以用以下图来描述librarycache的整体结构。

当一条SQL语句进入librarycache的时候,先将SQL文本转化为对应ASCII数值,然后对该这些ASCII数值进行hash函数的运算,传入函数的是SQL语句的名称〔name,对于SQL语句来说其name就是SQL语句的文本〕以及命名空间〔namespace,对于SQL语句来说是“SQLAREA〞,表示共享游标。可以从视图v$librarycache里找到所有的namespace〕。运用hash函数后得到一个值,该值就是hashbucket的号码,从而该SQL语句被分配到该号的hashbucket里去。实际上,hashbucket就是通过串连起来的对象句柄才表达出来的,它本身是一个逻辑上的概念,是一个逻辑组,而不像对象是一个具体的实体。oracle根据shared_pool_size所指定的sharedpool尺寸自动计算hashbuckets的个数,sharedpool越大,那么可以挂载的对象句柄就越多。

当某个进程需要处理某个对象时,比方处理一条新进入的SQL语句时,它会对该SQL语句应用hash函数算法,以决定其所在的hashbucket的编号,然后进入该hashbucket进行扫描并比较。有可能会发生该对象的句柄存在,但是句柄所指向的对象已经被交换出内存的情况出现。这时对应的对象必须被再次装载〔reload〕。也可能该对象的句柄都不存在,这时进程必须重新构建一个对象句柄挂到hashbucket上,然后再重新装载对象。SQL语句相关的对象有很多〔最直观的就是SQL语句的文本〕,这些对象都存放在librarycache里,它们都通过句柄来访问。可以把librarycache理解为一本书,而SQL语句的对象就是书中的页,而句柄就是目录,通过目录可以快速定位到指定内容的页。对象句柄存放了对象的名称〔name〕、对象所属的命名空间〔namespace〕、有关对象的一些标记〔比方对象是否为只读、为本地对象还是远程对象、是否被pin在内存中等等〕以及有关对象的一些统计信息等。而且,对象句柄中还存放了当前正在lock住和pin住该对象的用户列表、以及当前正在等待lock和pin该对象的用户列表。对象句柄中存放的最重要的内容就是指向Heap0对象的指针了。Heap0用来存放与对象有直接关系的一些信息,比方对象类型、对象相关的表〔比方依赖表、子表等〕、指向对象的其他数据块的指针〔这些数据块指向了实际存放SQL文本、PL/SQL代码、错误信息等的大内存块,这些大内存块依次叫做Heap1、2、3、4等〕等信息。

Heap是通过调用效劳器进程进行分配的,任何对象都具有heap0,至于还应该分配哪些其他的heap那么是由对象的类型决定的,比方SQL游标具有heap1和6,而PL/SQL程序包那么具有heap1、2、3和4。按照heap的使用情况,oracle会在SGA〔librarycache〕、PGA或UGA中分配heap,但是heap0始终都是在librarycache中进行分配的。如果所请求的heap已经在SGA中分配了,那么不会在PGA中再次分配heap。Heap是由一个或多个chunk组成的,这些chunk可以是分散的分布在librarycache中的,不需要连续分布。1)objecttype:librarycache中的对象类型包括:表、视图、索引、同名词等等。每个对象只能有一个objecttype,根据objecttype将对象归类到不同的namespace里。一个objecttype对应一个namespace,但是一个namespace可能对应多个objecttype。这样的话,查找一个对象时,只要在该对象所属的namespace中去找就可以了。比较常见的namespace包括:

a)SQLAREA:也可以叫做CRSR,表示sharedcursor,存放共享的SQL语句。

b)TABLE/PROCEDURE:存放的objecttype包括:table、view、sequence、synonym、procedure的定义、function的定义以及package的定义。

c)BODY:存放procedure的实际代码、function的实际代码以及package的实际代码。

d)TRIGGER:存放的objecttype为trigger。

e)INDEX:存放的objecttype为index。2)objectname:对象名称由三局部组成:

a)Schema的名称,对于共享游标〔SQL语句或PL/SQL程序块〕来说为空。

b)对象名称。分为两种情况:对于共享游标〔SQL语句或PL/SQL程序块〕来说,其对象名称就是SQL的语句本身;而对于其他对象〔比方表、视图、索引等〕就是其在数据字典中的名称。

c)Databaselink的名称。这是可选的,如果是本地对象,那么为空。

这样,对象的名称的格式为:SCHEMA.NAME@DBLINK。比方,可以为,也可以为hr.employees等。3)flags:flags主要用来描述对象是否已经被锁定。对象具有三种类型的flag:

a)publicflag:表示对象上没有锁定〔pin〕或者latch。

b)statusflag:表示对象上存在锁定〔pin〕,说明对象正在被创立或删除或修改等。

c)specitialflag:表示对象上存在librarycachelatch。4)tables:对每个对象,都会维护以下一串tables中的假设干个:

a)dependencytable:含有当前对象所依赖的其他对象。比方一个视图可能会依赖其组成的多个表、一个存储过程可能依赖其中所调用的其他存储过程、一个游标可能依赖其中所涉及到的多个表等。Dependencytable中的每个条目都指向一块物理内存,该物理内存中含有当前对象所依赖的对象的句柄。

b)childtable:含有当前对象的子对象,只有游标具有childtable。Childtable中的每个条目都指向一个可执行的SQL命令所对应的句柄。

c)translationtable:包含当前对象所引用的名称是如何解释为oracle底层对象的名称,只有游标具有translationtable。

d)authorizationtable:包含该对象上所对应的权限,一个条目对应一个权限。

e)accesstable:对于dependencytable中的每一个条目,都会在accesstable中存在对应的一个或多个条目。比方,假设对象A依赖对象B,那么在A的dependencytable和accesstable中都会存在一个条目指向B。位于accesstable中的指向B的条目说明了对B具有什么样的访问类型,从而也就说明了用户要执行A那么必须具有对B的权限。

f)read-onlydependencytable:类似于dependencytable,但是存放只读的对象。

g)schemanametable:包含authorizationtable中的条目所属的schema。5)datablocks:对象的其他信息会存放在不同的heap中,为了找到这些heap,会在heap0中存放多个〔最多16个,但是这16个datablock不会都用到〕datablocks结构,每个datablock含有指向这些实际heap内存块的指针。

除了heap0以外,还有11个heap,根据对象的不同进行分配,并存放了不同的内容:

1)Heap1:存放PL/SQL对象的源代码。

2)Heap2:存放PL/SQL对象的解析树,这有个好听的名字:DIANA。

3)Heap3:存放PL/SQL对象的伪代码。

4)Heap4:存放PL/SQL对象的基于硬件的伪代码。

5)Heap5:存放了编译时的错误信息。

6)Heap6:存放了共享游标对象的SQL文本。

7)Heap7:可用空间。

8)Heaps8–11:根据对象的不同而使用的子heap。我们可以通过查询v$db_object_cache来显示librarycache中有哪些对象被缓存,以及这些对象的大小尺寸。比方,我们可以用下面的SQL语句来显示每个namespace中,大小尺寸排在前3名的对象:select*from(selectrow_number()over(partitionbynamespaceorderbysharable_memdesc)size_rank,namespace,sharable_mem,substr(name,1,50)namefromv$db_object_cacheorderbysharable_memdesc)wheresize_rank<=3orderbynamespace,size_rank/转储librarycacheoracle提供了命令可以对librarycache中的内容进行转储。于是我们可以对librarycache进行转储,从而对上面所说的librarycache的内容进行验证。

ALTERSESSIONSETEVENTS'immediatetracenamelibrary_cachelevelN';

这里的N可以取的值分别为:

1转储librarycache的统计信息

2转储hash表的汇总信息

4转储librarycacheobject的根本信息

8转储librarycacheobject的详细信息

16转储heapsize的信息

32转储heap的详细信息

在测试之前,我们先创立一个测试表,然后再显示该表的数据。从而在librarycache中放入一些数据。翻开跟踪文件可以看到类似这样的信息,这实际就是v$librarycache里记录的信息,只不过v$librarycache中记录的是根据下面的信息合并汇总以后得到的。

我们分别以level4、8、16、32分别对librarycache进行转储,生成的转储文件分别以4#、8#、16#和32#来表示。翻开4#文件,然后直接查找“selectobject_id,object_namefromsharedpool_test〞,因为我们前面说到过,对于SQL语句来说,整个SQL语句的文本就是librarycacheobject的名称。于是,我们可以发现类似以下图四所示的内容:

这里是BUCKET105702。该bucket上只挂了一个对象,其对象句柄号为2cd433f8。在这个对象句柄里存放了很多信息,这里可以看到该对象的namespace为CRSR,也就是SQLAREA。可以看到该SQL语句的hash值为4d57861815002bfb42d03c9d2ecb9ce6。我们还可以看到很复杂的flags字段,它会包括很多标记,比方RON表示只读〔ReadOnly〕,SML表示当前句柄尺寸比较小〔Small〕等。而下面的lwt那么表示正在等待lock的对象列表〔LockWaiters〕,对应“LockWaiters〞;ltm那么表示临时正在持有lock的对象列表〔LockTemporary〕,对应“LockOwners〞;pwt那么表示正在等待pin的对象列表〔PinWaiters〕对应“PinWaiters〞;ptm那么表示临时正在持有pin的对象列表〔PinTemporary〕,对应图“PinOwners〞。再往下看,可以看到CHILDREN局部,这局部就是前面所说过的子游标的信息了。实际上,指向heap0的指针也位于这一局部,这个指针也就是2cd43314。这里显示的是一个handle寻找定位heap0我们翻开8#文件,查找2cd43314,可以看到如以下图所示的内容。这就是heap0中所包含的内容。可以看到该heap0的handle正是2cd43314,type为CRSR。还可以看到几个重要的table,这些table都是我们前面介绍过的,包括DEPENDENCIES、ACCESSES、TRANSACTIONS。从前面我们已经知道dependencytable记录的是SQL语句所依赖的对象,这里我们可以看到我们的SQL语句依赖一个对象,同时该对象的handle为2cd44348,很明显,它一定指向sharedpool_test表。同时,我们可以看到transactiontable所记录的oracle底层解析的对象的handle也是2cd44348,它与dependencytable所记录的对象是一样的,说明这个表是实实在在的表,而不是一个同名词。我们可以看到最后一局部是DATABLOCKS,从我们前面介绍过的内容可以知道这局部的记录指向了其他的heap内存块。我们从data#列上可以知道,该SQL存在两个相关的heap,编号为0和6。我们知道,heap0存放了SQL语句本身所涉及到的对象以及假设干种表等的信息,而heap6那么存放了SQL语句的文本、执行方案等。我们可以到32#文件中查找33e8ff08〔heap0〕和310ac968〔heap6〕我们继续在8#文件里查找2cd44348,也就是找到librarycache中记录SQL所引用的对象的局部。我们可以看到类似以下图所示的内容。从name列中可以看到,该对象正是sharedpool_test表,同时该表所在的schema为COST。而且从type为TABL也可以看到,对象sharedpool_test是一个表。如以下图所示。我们同时可以看到owner的值,实际上这正是在图五中的object的代号。同时从heap的name处也可以看到,heap0为Pcursor,而heap6为sqlarea,这也说明了这两个不同的heap所存放的不同内容。

dictionarycache概述递归调用dictionarycache专门用来存放SYSschema所拥有的对象的内存区域。使用dictionarycache时以行为单位,而不像其他比方buffercache以数据块为单位,因此dictionarycache也叫做rowcache。构造dictionarycache的目的是为了加快解析SQL语句的速度,因为dictionarycache里存放了所有表的定义、Storage信息、用户权限信息、约束定义、回滚段信息、表的统计信息等。而这些信息都是在解析过程中必须用到的。假设oracle在解析SQL的过程中,发现dictionarycache里没有该SQL所引用的表的定义信息,那么oracle必须到磁盘上system表空间里找到这个引用表的定义信息,并将这些定义信息加载到dictionarycache里。这个从磁盘上获取数据字典数据的过程就叫做递归SQL〔RecursiveSQL〕。通常来说,当我们执行一条新的SQL语句时,都会产生很屡次的递归调用,也会产生很多的递归SQL。比方我们来下面这个例子。假设oracle在解析SQL的过程中,发现dictionarycache里没有该SQL所引用的表的定义信息,那么oracle必须到磁盘上system表空间里找到这个引用表的定义信息,并将这些定义信息加载到dictionarycache里。这个从磁盘上获取数据字典数据的过程就叫做递归SQL〔RecursiveSQL〕。通常来说,当我们执行一条新的SQL语句时,都会产生很屡次的递归调用,也会产生很多的递归SQL。比方我们来下面这个例子。从这里可以很明显看到执行该SQL产生了1227次的递归调用,这227次的递归调用将表sharedpool_test相关的信息,比方列定义、统计信息等,都加载到了dictionarycache里。当我们再次执行该SQL时,会发现recursivecalls变成了0,因为dictionarycache里已经包含解析SQL所需要参照的数据字典了。

转储dictionarycache

我们可以使用如下命令对dictionarycache进行转储。

ALTERSESSIONSETEVENTS'immediatetracenamerow_cachelevelN';

这里的N可以取的值分别为:

1转储dictionarycache的统计信息;

2转储hash表的汇总信息;

8转储dictionarycache中的对象的结构信息;

如果对level1进行转储,可以看到转储出来的内容,很明显,就是v$rowcache里的内容。每一种数据字典都有一行记录来表示。比方有tablespace相关的数据字典等。如果以level2转储的话,可以看到类似如下的内容。这里有34个hash表对dictionarycache中的对象进行管理,每个hash表都对应了一种数据字典,同时有一个名为rowcacheobjects的latch来控制并发访问。可以看到,v$latch_children里名为“rowcacheobjects〞的记录数量也是34。解析SQL语句的过程解析分为硬解析和软解析。当一句SQL第一次被执行时必须进行硬解析。

1、第一步当客户端发出一条SQL语句〔也可以是一个存储过程或者一个匿名PL/SQL块〕进入sharedpool时〔注意,我们从前面已经知道,oracle对这些SQL不叫做SQL语句,而是称为游标〔cursor〕。因为oracle在处理SQL时,需要很多相关的辅助信息,这些辅助信息与SQL语句一起组成了游标〕,oracle首先将SQL文本转化为ASCII字符,然后根据hash函数计算其对应的hash〔hash_value〕。根据计算出的hash值到librarycache中找到对应的bucket,然后比较bucket里是否存在该SQL语句。2、第二步如果不存在,那么需要按照我们前面所描述的,获得sharedpoollatch,然后在sharedpool中的可用chunk链表〔也就是bucket〕上找到一个可用的chunk,然后释放sharedpoollatch。在获得了chunk以后,这块chunk就可以认为是进入了librarycache。然后,进行硬解析过程。3、第三步硬解析包括以下几个步骤:

1)对SQL语句进行语法检查,看是否有语法错误。比方没有写from等。如果有,那么退出解析过程。

2)到数据字典里校验SQL语句涉及的对象和列是否都存在。如果不存在,那么退出解析过程。

3)将对象进行名称转换。比方将同名词翻译成实际的对象等。如果转换失败,那么退出解析过程。

4)检查游标里用户是否具有访问SQL语句里所引用的对象的权限。如果没有权限,那么退出解析过程。

5)通过优化器创立一个最优的执行方案。这一步是最消耗CPU资源的。

6)将该游标所产生的执行方案、SQL文本等装载进librarycache的假设干个heap中。

4、第四步在硬解析的过程中,进程会一直持有librarycachelatch,直到硬解析结束。硬解析结束以后,会为该SQL产生两个游标,一个是父游标,另一个是子游标。父游标里主要包含两种信息:SQL文本以及优化目标〔optimizergoal〕。父游标在第一次翻开时被锁定,直到其他所有的session都关闭该游标后才被解锁。当父游标被锁定的时候是不能被交换出librarycache的,只有在解锁以后才能被交换出librarycache,这时该父游标对应的所有子游标也被交换出librarycache。子游标包括游标所有的信息,比方具体的执行方案、绑定变量等。5、第五步子游标随时可以被交换出librarycache,当子游标被交换出librarycache时,oracle可以利用父游标的信息重新构建出一个子游标来,这个过程叫reload。可以使用下面的方式来确定reload的比率:父游标句柄子游标句柄HEAP0HEAP6子游标信息一个父游标可以对应多个子游标。子游标具体的个数可以从v$sqlarea的version_count字段表达出来。而每个具体的子游标那么全都在v$sql里表达。当具体的绑定变量的值与上次的绑定变量的值有较大差异〔比方上次执行的绑定变量的值的长度是6位,而这次执行的绑定变量的值的长度是200位〕时或者当SQL语句完全相同,但是所引用的对象属于不同的schema时,都会创立一个新的子游标。软解析分类1)第一种是某个session发出的SQL语句与librarycache里其他session发出的SQL语句一致。这时,该解析过程中可以去掉硬解析中的5和6这两步,但是仍然要进行硬解析过程中的2、3、4步骤:也就是表名和列名检查、名称转换和权限检查。

2)第二种是某个session发出的SQL语句与librarycache里该同一个session之前发出的SQL语句一致。这时,该解析过程中可以去掉硬解析中的2、3、5和6这四步,但是仍然要进行权限检查,因为可能通过grant改变了该session用户的权限。

3)第三种是当设置了初始化参数session_cached_cursors时,当某个session对相同的cursor进行第三次访问时,将在该session的PGA里创立一个标记,并且该游标即使已经被关闭也不会从librarycache中交换出去。这样,该session以后再执行相同的SQL语句时,将跳过硬解析的所有步骤。这种情况下,是最高效的解析方式,但是会消耗很大的内存。我们先来举一个例子说明如果在解析过程中发生语法或语义错误时,在sharedpool中是怎样表达的。

SQL>selectobject_typefrommsharedpool_test111;

ORA-00942:表或视图不存在

然后我们以level16转储librarycache,并翻开转储文件,找到相应的局部,可以看到,

该SQL语句在语法上是错误的〔from写成了fromm〕,oracle仍然在sharedpool中为其分配了一个chunk,然后该chunk进入librarycache,并在librarycache中分配了一个bucket,同时也生成了heap0,但是该heap0中不存在相应的一些如dependencytable等table的局部,以及datablock的局部。oracle始终都是先对SQL生成hash值〔不管该SQL语法上是否正确〕,再根据hash值到对应的可用chunk链表〔也就是bucket〕里分配chunk,然后进入语法解析等解析过程。我们再举一个例子来说明解析正确的SQL语句的过程。如下所示。另个使用了绑定变量的SQL语句,语句名字完全一样,但是绑定变量的数据类型不一致。我们以level16来转储librarycache。可以看到如下图的内容。很明显的看到,子游标的局部包含两条记录,这也就说明该SQL语句产生了两个子游标。虽然我们从SQL文本上看,前后两次执行的SQL语句是一样的。只有绑定变量的类型发生了改变,第一次是number型,而第二次是varchar2型。可正是这数据类型的变化导致了该SQL语句的执行方案不能得到共享,从而产生了两个子游标。这时,我们根据子游标的两个handle:33e12868和33e393c0找到对应的heap0的话,就可以看到这两个heap0中所记录的heap6是两个完全不同的内存块,这也说明前后两次执行SQL并没有真正得到共享。从记录父游标的视图v$sqlarea的version_count列可以看到,该SQL语句有2个子游标。而从记录子游标的视图v$sql里可以看到,该SQL文本确实有两条记录,而且它们的SQL文本所处的地址〔address列〕也是一样的,但是子地址〔child_address〕却不一样。这里的子地址实际就是子游标所对应的heap0的句柄。

由此我们也可以看到,存在许多因素可能导致SQL语句不能共享。常见的因素包括,SQL文本大小写不一致、SQL语句的绑定变量的类型不一致、SQL语句涉及到的对象名称虽然一致但是位于不同的schema下、SQL的优化器模式不一致〔比方添加提示、修改了optimizer_mode参数等〕等。librarycache的并发控制(latch,lock,pin)为什么需要并发控制?由于librarycache是可以被所有进程同时访问并修改的,因此就必然存在一个并发控制的问题。比方对于前面我们举例子来说,第一次使用number类型的绑定变量执行的SQL语句产生的游标挂在bucket22544上。而当我们第二次使用varchar2类型的绑定变量再次执行该SQL语句时,oracle需要访问该bucket22544上的句柄,发现不能共用执行方案时,还要修改该句柄,向CHILDREN局部添加一条指向另外一个子游标的句柄。在很多进程并发执行的情况下,那么当修改挂在bucket22544上的句柄的时候,必须防止其他进程同时修改所访问的句柄。因为如果不防止这种情况的出现,那么假设这时正好也有一个进程也是使用varchar2类型的绑定变量执行该相同的SQL时,那么也会向CHILDREN局部添加一条子游标的记录,那么CHILDREN局部就会出现两条varchar2的执行方案,而实际上这两个执行方案是一样的,是完全可以合二为一的,这样也就达不到SQL共享的目的。同时还要考虑,当oracle在向某个heap〔比方heap0和heap6〕填入SQL文本、执行方案等数据的过程中,要防止该heap又被其他进程分配掉的情况出现。如果不防止的话,那这个heap的数据就被两个进程同时写,那里面的数据一定是混乱而无法使用的了。为了有效的解决上面所说的并发性的问题,oracle使用三种结构来完成对librarycache的并发控制:lock、pin和librarycachelatch。简单来说,进程如果要访问或者修改librarycache里的对象,首先必须获得librarycachelatch,然后获得handle上的lock,最后获得heap上的pin,访问或修改结束以后,释放pin、lock和latch。

lock是落在librarycache里的对象句柄上的,用来管理并发性。按照前面所说的例子,当多个进程同时修改bucket22544上的句柄的时候,只有一个进程能够获得该句柄上的lock,其他进程必须等待〔表达的等待事件就是librarycachelock〕。同时,尝试获得某个句柄上的lock也是将游标句柄对象加载到sharedpool里的唯一方式。也就是说,当客户端发出某个SQL语句时,oracle对该SQL语句运用hash函数生成hash值,然后到该hash值所对应的librarycache的bucket里试图找到对应的句柄并lock该句柄时,如果发现该句柄不存在〔可能是由于该SQL语句是一条全新的SQL语句,或者以前该SQL语句执行过但是现在被交换出了librarycache〕,那么会将该SQL游标所对应的句柄加载到librarycache里。目前有三种lock模式,分别是:share、exclusive和null。如果某个进程只是要读取句柄里的信息时,会对该句柄添加share模式的lock,比方当编译某个存储过程时,进程会去读取该存储过程所引用的子存储过程等,这时其他进程可以对该子存储过程添加share和null模式的lock;如果某个进程需要修改对象里的信息时,就会对该句柄添加exclusive模式的lock,比方删除某个存储过程就会添加exclusive模式的lock,这时其他进程只能对该相同的句柄添加null模式的lock;null模式的lock比较特殊,在任何可以执行的对象上〔比方存储过程、视图、函数等等〕都拥有该null模式的lock。你可以随意打破该模式的lock,这时拥有该LOCK的对象就失效了,需要重新编译。当SQL开始解析时,或获得null模式的lock,然后会一直加在该对象上,直到某些会引起对象失效的DDL发生在对象或对象所依赖的其他对象上,这时该lock被打破。当发生null模式的lock时,其他进程可以对该相同的句柄添加任何模式的lock。Null模式的锁主要是为了解决对象的依赖性问题。pin那么是落在heap上的,用来防止多个进程同时更新同一个heap。pin的优先级比lock要低,获得pin之前必须先获得lock。同样按照前面所说的例子,当第二次使用varchar2类型的绑定变量执行相同的SQL语句时,该进程首先会获得bucket22544的句柄上的lock,根据该句柄里所记录的heap发现不能共用时,到sharedpool中分配可用的chunk作为heap〔包括heap0和heap6等〕的空间,并获得该heap上的pin,然后在句柄里添加一条子游标记录,以指向所分配的heap0的句柄。当pin住了heap以后,进程就向heap中写入数据,结束以后释放pin,最后释放lock。当某个进程获得了句柄上的lock,但是不能pin住该句柄所对应的heap时,该进程就必须等待〔表达的等待事件就是librarycachpin〕。与lock相同,当进程试图pin住某个heap但是发现该heap不存在时,就会同时将该heap加载到librarycache里同时pin住它。pin有两种模式:share和exclusive。当某个进程只需要读取heap中的信息时,会对该heap执行share模式的pin。如果进程需要修改heap时,那么会先对该heap执行share模式的pin以便对heap进行错误和平安检查,通过以后,再对该heap执行exclusive模式的pin,从而对该heap进行修改。从上面对lock和pin的描述中可以看出,lock本身不是一个原子的操作,也就是说要完成lock需要执行一系列的操作步骤〔包括pin住heap等〕。因此为了防止lock的过程被其他进程打破,oracle使用librarycachelatch来管理lock。也就是说,如果某个进程在进行lock之前,必须先获得librarycachelatch,如果不能获得该latch,就必须等待。当lock过程结束以后,释放该latch。

注意:latch锁住的是整个的bucket。注意:latch是串行的,latch的单位是bucket。首先获得bucket上的latch,然后去获得Handle上的Lock,最后去pin住Heap。当Lock和Pin完成以后,oracle会释放latch。因此latch持有的过程就是为了获取lock或者pin,因此latch不是长时间持有,因为它是串行的。oracle提供了多个librarycachelatch〔这样,每个librarycachelatch都称为子latch〕来保护librarycache中的bucket。这些子latch的数量由一个隐藏参数决定:_kgl_latch_count。该参数缺省值为大于等于系统中CPU个数的最小的素数。比方在一个具有4个CPU的生产环境中,librarycachelatch的个数为5,如下所示。但是oracle内部规定了librarycachelatch的最大个数为67,即便将这个隐藏参数设置为100,librarycachelatch的数量也还是67个。具体到每个bucket应该由哪个子latch来管理,那么是通过下面这个函数来确定的。

latch号=mod(bucket号,latch的数量)

假设还是按照上面的例子,对于bucket64367来说,假设当前系统具有37个librarycachelatch,那么会使用24〔mod(64367,37)=24〕号latch来保护挂在该bucket上的句柄。正是由于这样的算法,可能会导致所有的子latch不能在librarycache里的整个bucket链条上均匀分布,有可能出现某个或某几个子latch非常繁忙,而有些子latch那么非常空闲。至于如何判断以及解决,可以见下面sharedpool的优化局部。我们来做两个测试,分别来模拟一下lock和pin。来看看lock和pin是如何控制librarycache里的对象的。实验的思路很简单第一,翻开一个session〔sess#1〕创立一个存储过程,该过程只做一件事情,就是通过调用dbms_lock.sleep进行等待。并在sess#1中调用该存储过程;第二,翻开第二个session〔sess#2〕,重新编译该存储过程;第三,翻开第三个session〔sess#3〕,删除该存储过程;第四,翻开第四个session〔sess#4〕进行监控。根据前面对lock和pin的描述,我们可以预见,sess#2将等待librarycachepin。而sess#3会等待librarycachelock。

实验过程如下,在实验的过程中,不断以level16转储librarycache以更深入的观察lock和pin的变化,以下按照时间顺序排列:Session1#:建立存储过程,执行存储过程Session4#,dump,编号F1sess#2sess#4dump,编号F2sess#3sess#4,转储出来的文件编号为F3从监控的结果看到,正如我们所预料的,编译存储过程的sess#2〔sid为153〕正在等待librarycachepin,而删除存储过程的sess#3〔sid为148〕正在等待librarycachelock。在转储出来的文件中,我们主要关存储过程lock_test本身在librarycache中的变化。在F1中,我们可以看到如以下图的内容。注意其中的lock为N,pin为S。由于sess#1正在执行lock_test存储过程,需要读取该handle所对应的heap里的内容,因此以null模式lock住句柄,同时以share模式pin住了heap。这时该对象句柄可以被其他进程以任何模式锁定,但是该句柄对应的heap只能被其他进程以share模式pin,而不能以exclusive模式pin。在转储出来的文件中,我们主要关存储过程lock_test本身在librarycache中的变化。在F1中,我们可以看到如图的内容。注意其中的lock为N,pin为S。由于sess#1正在执行lock_test存储过程,需要读取该handle所对应的heap里的内容,因此以null模式lock住句柄,同时以share模式pin住了heap。这时该对象句柄可以被其他进程以任何模式锁定,但是该句柄对应的heap只能被其他进程以share模式pin,而不能以exclusive模式pin。我们翻开发出编译命令以后生成的F2,找到图中局部。由于sess#2会对存储过程lock_test进行编译,因此需要重新刷新该对象的heap中的信息。所以需要以exclusive模式lock住该对象的句柄,同时以exclusive模式pin住该对象的heap。这时,由于当前句柄上存在null模式的lock,因此sess#2申请exclusive的lock能够成功,但是由于当前该句柄对应的heap上已经存在share的pin,因此申请exclusive的pin时,必须等待,这时表达为sess#2等待librarycachepin。

我们发出删除命令以后,很明显的,要删除存储过程lock_test,sess#3必须以exclusive模式获得lock_test句柄的lock。而这时该句柄上已经存在了exclusive模式的lock,于是这时sess#3只有等待sess#2所添加的exclusive模式的lock释放以后才能继续进行。表达在v$session_wait等相关视图里就是等待librarycachelock。这时,我们甚至可以发现,整个“dropprocedurelock_test〞命令都没有出现在librarycache里。也就是说,oracle已经为该SQL语句分配了chunk,但是由于无法获得所引用对象的lock,从而使得所分配的chunk还没有能够挂到bucket上去,也就还没有进入librarycache里。

至于如何诊断以及解决这两个等待事件的话,可以见下面sharedpool的优化局部。共享SQL语句根据上面对sharedpool的内部原理的说明,我们已经很清楚的知道,oracle引入sharedpool就是为了能够缓存经常使用的SQL语句,从而能够将SQL语句的执行方案缓存在librarycache中,这样当第二次执行相同的SQL语句时,就可以跳过硬解析而进行软解析,从而节省了大量的CPU资源。当一句新的SQL语句进入sharedpool时,需要分配chunk,这时会持有sharedpoollatch,直到获得chunk,这是一个潜在的争用点;获得chunk以后,进入librarycache时,需要获得librarycachelatch来保护对lock的获得,这又是一个潜在的争用点。oracle要lock住句柄,才能往里填写内容,这也是一个潜在的争用点;生成执行方案等内容以后,oracle还要pin住假设干个heap,才能往里写入实际的数据,这还是一个潜在的争用点。可见,一句新的SQL语句从进入sharedpool开始到解析结束,存在一系列的争用点。特别是,当并发用户很多的时候,每个用户都发出对于sharedpool来说是新的SQL语句,这时,你会看到CPU非常繁忙,甚至一直处于100%的使用状态,同时这些潜在的争用点都将变成实际的争用点,表现出来就是等待事件非常多,用户响应缓慢甚至没有响应。绑定变量、SQL书写格式统一为了尽可能减少新的SQL语句,尽可能多的缓存SQL语句,就必须使得应用程序的SQL语句尽量保持一致,包括各个单词之间的空格一致以及大小写一致等。其中最重要的一点就是要使用绑定变量。对于一个系统来说,SQL语句本身所引用的表和列都是有限的,只有SQL语句中所引用的数据才是无限的,因此将SQL语句中所涉及到的数据都用绑定变量来替代,这样就能使得对于不同的数据,SQL语句看起来都是一样的。判断当前系统是否使用了绑定变量,可以使用如下语句获得当前系统的硬解析次数与解析总次数的比例。硬解析次数越少越好,这个比例也越接近于0越好。selectt.valueastotal,h.valueashard,round(h.value/t.value,2)asratio_hardtototalfromv$sysstatt,v$sysstathwhere='parsecount(total)'and='parsecount(hard)'

如果发现硬解析比较高,那么可以使用下面的方法找到sharedpool里那些没有使用绑定变量的SQL语句,从而提交给开发人员进行修改。breakonplan_hash_valueonexecntonhash_valueskip1selectd.plan_hash_valueplan_hash_value,d.execntexecnt,a.hash_valuehash_value,a.sql_textsql_textfromv$sqltexta,(selectplan_hash_value,hash_value,execntfrom(selectc.plan_hash_value,b.hash_value,c.execnt,rank()over(partitionbyc.plan_hash_valueorderbyb.hash_value)ashashrankfromv$sqlb,(selectcount(*)asexecnt,plan_hash_valuefromv$sqlwhereplan_hash_value<>0groupbyplan_hash_valuehavingcount(*)>3orderbycount(*)desc)cwhereb.plan_hash_value=c.plan_hash_valuegroupbyc.plan_hash_value,b.hash_value,c.execnt)wherehashrank<=3)dwherea.hash_value=d.hash_valueorderbyd.execntdesc,a.hash_value,a.piece/如果发现系统中大量的没有使用绑定变量,而且系统是由其他第三方供给商提供的,不能做大量的修改从而使用绑定变量。实际上,这样的系统根本就是一个失败的系统,但是如果必须继续使用而又希望能够尽量减少对CPU资源的争用,oracle还提供了一个参数:cursor_sharing。该参数缺省是exact,表示不对传入sharedpool中的SQL语句改写。如果设置为similar或force,那么oracle会对SQL语句进行改写,将SQL语句中值的局部都用系统生成的变量来替代,从而到达与绑定变量相同的目的。similar表示,当SQL语句中的数值所在的列存在直方图〔histogram〕信息时,oracle不对SQL语句进行改写,就像设置为exact一样,每次对于不同的值都要进行硬解析;而当表没有经过分析,不存在直方图时,oracle会对SQL语句进行改写,就像设置为force一样,这样每次对于不同的值都会进行软解析。但是使用这种方法在不同的oracle版本中可能存在bug,需要在测试环境中仔细测试。同时,将cursor_sharing设置为similar或force以后,会在生成执行方案上产生一些副作用,比方选择错误的索引,以及忽略带有数值的函数索引〔比方函数索引为substr(colname,1,6)的情况,因为其中的1和6被系统变量替代了〕等sharedpool的设置优化设置sharedpool的大小来说,没有一个通用的、普遍适用的值,不同的系统负载需要不同大小的sharedpool来管理。通常我们在设置sharedpool时,应该遵循“不要太大、也不要太小〞的原那么,设置一个初始的值,然后让系统正常运行一段时间,在这段时间里,对sharedpool的使用情况进行观察监控,最后根据系统的负载得出一个在当前负载下比较合理的值。注意,这里只是说明是在当前负载下,如果随着系统的不断升级,导致负载发生一个质的变化,这时又需要对sharedpool重新监控并做成调整了。

设置1G以上的sharedpool不会给性能带来任何的提高,相反,这将给oracle管理sharedpool以及监控sharedpool的过程中会带来更多的麻烦。我们可以在系统上线时,设置sharedpool为SGA的10%,但是不要超过1G,让系统正常运行一段时间,然后我们可以借助9i以后所引入的advisory来帮助我们判断sharedpool设置是否合理。

只要将初始化参数:statistics_level设置为typical〔缺省值〕或all,就能启动对sharedpool的建议功能,如果设置为basic,那么关闭建议功能。使用如下的SQL语句显示oracle所建议的sharedpool的大小。SELECTshared_pool_size_for_estimate,estd_lc_size,estd_lc_memory_objects,estd_lc_time_saved,estd_lc_time_saved_factor,estd_lc_memory_object_hitsFROMv$shared_pool_advice/第一列表示oracle所估计的sharedpool的尺寸值,其他列表示在该估计的sharedpool大小下所表现出来的指标值,具体含义可以参见oracle的联机帮助。我们主要关注estd_lc_time_saved_factor列的值,当该列值为1时,表示再增加sharedpool对性能的提高没有意义。对于上例来说,当sharedpool为56M时,到达最正确大小。对于设置比56M更大的sharedpool来说,就是浪费空间,没有意义了。SELECT'SharedPool'component,shared_pool_size_for_estimateestd_sp_size,estd_lc_time_saved_factorparse_time_factor,CASEWHENcurrent_parse_time_elapsed_s+adjustment_s<0THEN0ELSEcurrent_parse_time_elapsed_s+adjustment_sENDresponse_timeFROM(SELECTshared_pool_size_for_estimate,shared_pool_size_factor,estd_lc_time_saved_factor,a.estd_lc_time_saved,e.VALUE/100current_parse_time_elapsed_s,c.estd_lc_time_saved-a.estd_lc_time_savedadjustment_sFROMv$shared_pool_advicea,(SELECT*FROMv$sysstatWHERENAME='parsetimeelapsed')e,(SELECTestd_lc_time_savedFROMv$shared_pool_adviceWHEREshared_pool_size_factor=1)c)/我们还可以借助v$shared_pool_advice来观察不同的sharedpool尺寸情况下的响应时间〔单位是秒〕各是多少:

sharedpool的统计信息有关sharedpool的最重要的统计信息就是parsecount(total)和parsecount(hard),parsecount(total)表示解析的总次数,而parsecount(hard)表示硬解析的次数,这个值应该越小越好。select*fromv$sysstatwherenamein('parsecount(total)','parsecount(hard)')/对于libra

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论