共享池( shared pool)

1、共享次(shared pool)

共享池是组成SGA的重要结构中的一个。可以通过以下命令确认SGA结构。

SQL> show sga;

Total System Global Area 9620525056 bytes
Fixed Size		    2215704 bytes  --固定区域
Variable Size		 8522825960 bytes  --可变区域
Database Buffers	 1073741824 bytes
Redo Buffers		   21741568 bytes

除ShowSga外,我们还可以用V$sgastat视图显示SGA各内存结构的大小

  1. SQL> select * from v$sgastat where rownum < 11;  
  2.   
  3. POOL         NAME                                BYTES  
  4. ------------ ------------------------------ ----------  
  5.              fixed_sga                         1339824  
  6.              buffer_cache                    293601280  
  7.              log_buffer                        5132288  
  8. shared pool  dpslut_kfdsg                          256  
  9. shared pool  hot latch diagnostics                  80  
  10. shared pool  kkj jobq  wor                        4104  
  11. shared pool  vips_package_file                     924  
  12. shared pool  ENQUEUE STATS                       16296  
  13. shared pool  sskgplib                             1052  
  14. shared pool  transaction                        426316  
  15.   
  16. 已选择10行。  

在一个很高的层次上来看,shared pool可以分为库缓存(library cache)和数据字典缓存(dictionary cache)。Library cache存放了最近执行的SQL语句、存储过程、函数、解析树以及执行计划等。dictionary cache则存放了在执行SQL语句过程中,所参照的数据字典的信息,包括SQL语句所涉及的表名、表的列、权限信息等。dictionary cache也叫做row cache,因为这里面的信息都是以数据行的形式存放的,而不是以数据块的形式存放的。共享池的内存区域组成,可以通过如下命令查看:

SQL> select count(*) from v$sgastat where pool = 'shared pool';

  COUNT(*)
----------
       897   --总共分为897个内存区域

共享池的结构大体上如下分类:
Permanent Area:process,session,segment array(enqueue,transaction ...)等。进程列表、会话列表、Enqueue列表、事务列表等的资源分配到共享池的永久区域(permanent area),与实例的寿命相同。
Library Cache:管理执行sql语句必要的全部对象(sql、表、视图、procedure等)信息。
Dictionary Cache:也叫做row cache,管理oracle所使用的字典(dictionary)信息。
Reserved Area:保留区域。为动态分配内存,oracle将分配部分保留区域。

oracle对SQL语句进行了概括和抽象,将SQL语句提炼为两部分,一部分是SQL语句的静态部分,也就是SQL语句本身的关键词、所涉及的表名称以及表的列等。另一部分就是SQL语句的动态部分,也就是SQL语句中的值(即表里的数据)。


从上面这个图中可以看到,当SQL语句进入library cache时,oracle会到dictionary cache中去找与sharedpool_test表有关的数据字典信息,比如表名、表的列等,以及用户权限等信息。如果发现dictionary cache中没有这些信息,则会将system表空间里的数据字典信息调入buffer cache内存,读取内存数据块里的数据字典内容,然后将这些读取出来的数据字典内容按照行的形式放入dictionary cache里,从而构造出dc_tables之类的对象。然后,再从dictionary cache中的行数据中取出有关的列信息放入library cache中。

共享池是利用堆这种内存管理方法进行管理。从一个物理的层面来看,shared pool是由许多内存块组成,这些内存块通常称为chunk.Chunk是shared pool中内存分配的最小单位,一个chunk中的所有内存都是连续的。这些chunk可以分为四类,这四类可以从x$ksmsp(该视图中的每个行都表示shared pool里的一个chunk)的ksmchcls字段看到:

1) free:(即马上使用)这种类型的chunk不包含有效的对象,可以不受限制的被分配。
2) recr:意味着recreatable(可再性),这种类型的chunks里包含的对象可以在需要的时候被临时移走,并且在需要的时候重新创建。比如对于很多有关共享SQL语句的chunks就是recreatable的。
3) freeabl:这种类型的chunks包含的对象都是曾经被session使用过的,并且随后会被完全或部分释放的。这种类型的chunks不能临时从内存移走,因为它们是在处理过程中间产生的,如果移走的话就无法被重建。

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

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

  1. SQL> alter session set events 'immediate trace name heapdump level 2';  
  2.   
  3. 会话已更改。  
  4.   
  5. select d.value || '/' || lower(rtrim(i.instance, chr(0))) || '_ora_' ||  
  6.   2         p.spid || '.trc' trace_file_name  
  7.   3    from (select p.spid  
  8.   4            from sys.v$mystat m, sys.v$session s, sys.v$process p  
  9.   5           where m.statistic# = 1  
  10.   6             and s.sid = m.sid  
  11.   7             and p.addr = s.paddr) p,  
  12.   8         (select t.instance  
  13.   9            from sys.v$thread t, sys.v$parameter v  
  14.  10           where v.name = 'thread'  
  15.  11             and (v.value = 0 or t.thread# = to_number(v.value))) i,  
  16.  12         (select value from sys.v$parameter where name = 'user_dump_dest') d;  
  17.   
  18. TRACE_FILE_NAME  
  19. ---------------------------------------------------------------------------------------------------  
  20. /u01/app/diag/rdbms/orcl/orcl/trace/orcl_ora_3844.trc  

然后打开产生的转储文件,找到“FREE LISTS”部分:

  1. FREE LISTS:  
  2.  Bucket 0 size=16  
  3.  Bucket 1 size=20  
  4.  Bucket 2 size=24  
  5.   Chunk 51ffffe8 sz=       24    free      "               "  
  6.  Bucket 3 size=28  
  7.  Bucket 4 size=32  
  8.  Bucket 5 size=36  
  9.  Bucket 6 size=40  
  10.  Bucket 7 size=44  
  11.  Bucket 8 size=48  
  12.  Bucket 9 size=52  
  13.  Bucket 10 size=56  
  14.  Bucket 11 size=60  
  15.  Bucket 12 size=64  
  16.  Bucket 13 size=68  
  17.  Bucket 14 size=72  
  18.  Bucket 15 size=76  
  19.  Bucket 16 size=80  
  20.  Bucket 17 size=84  
  21.  Bucket 18 size=88  
  22.  Bucket 19 size=92  
  23.   Chunk 523fffa4 sz=       92    free      "               "  
  24.  Bucket 20 size=96  
  25.  Bucket 21 size=100  
  26. ... ...  

欲从共享池的堆分配内存的所有进程,必须获得shared pool锁存器。发生Hard Parsing时,进程从共享池分配到新sql语句所需的存储空间,此时必须获得shared pool锁存器。shared pool锁存器基本上全实例上只有一个,且需要在分配必要内存(chunk)的全过程一直拥有。因此,多个进程同时使用共享池内存时,在获取锁存器的过程中会发生争用。获取shared pool锁存器过程中发生争用,则等待latch: shared pool事件。
oracle 9i以上版本开始,共享次可分为多个副池(最多7个)进行管理。利用_KGHDSIDX_COUNT隐含参数,可管理副池的数量。因此,共享池较大时分为多个副池管理,所以能减少shared pool锁存器争用。通过如下语句可以看见数据库中的shared pool数量:

  1. SQL> select count(*) from v$latch_children where name = 'shared pool';  
  2.   
  3.   COUNT(*)  
  4. ----------  
  5.          7  

在shared pool上面的等待事件就是:

  1. SQL> select name,parameter1,parameter2,parameter3 from v$event_name where name like 'latch: shared pool';  
  2.   
  3. NAME                           PARAMETER1           PARAMETER2           PARAMETER3  
  4. ------------------------------ -------------------- -------------------- --------------------  
  5. latch: shared pool             address              number               tries  


 

2.库高速缓冲区(library cache)结构

共享池中最关键的部分是库高速缓冲区,它是管理与sql语句的执行相关的所有信息的区域。库高速缓冲区是Hash Table -> Bucket -> Chain -> Handle -> Object的结构。可以把library cache理解为一本书,而SQL语句的对象就是书中的页,而句柄就是目录,通过目录可以快速定位到指定内容的页。

oracle 利用应用于对象名称上的Hash函数生成的Hash值,分配适当的Hash Bucket,拥有相同Hash值的对象通过Chain(列)管理。一个Library Cache Handle(以下简称Handle)管理一个Library Cache Object(以下简称LCO)。Handle对实际LCO起到meta信息和指针作用,LCO保存着实际信息。LCO所包含的信息中重要信息如下:
Dependency Table:当前LCO依赖其它LCO的信息。
Child Table:关于当前LCO的子LCO的信息。
Data Blocks:LCO包含的实际信息(数据)所存储的chunk区域的指针信息。

欲检索库高速缓冲区的所有进程,就必须获得保护相应Hash Bucket的Library cache锁存器。接近库高速缓冲区的过程中发生Library cache锁存器争用时,进程等待latch: library cache事件。
如果library cache锁存器用于库高速缓冲区检索的同步,library cache lock和library cache pin这两个TX锁就会起到保护Handle和LCO的所用。如利用alter table ... 命令修改表的进程,对存储表信息的LCO,必须以Exclusive模式获得library cache lock。如果在获得library cache lock和library cache pin过程中发生争用,就会各自等待library cache lock事件和library cache pin事件。


3、sql的执行

用户请求执行sql,oracle则会利用上面说明的内存和锁存器执行必要的工作。将这些内容按时间整理结果如下:
(1)用户请求执行新sql时,oracle在执行基本语法和权限检查等步骤后,获得Hash Bucket的library cache锁存器,然后确认库高速缓冲区上是否存在相同的sql,即相同的LCO。若在获得library cache锁存器过程中发生争用,则等待latch: library cache事件。存在相同LCO存在时直接跳至第(8)阶段执行,此过程称之为soft parsing。每当发生sql parsing请求时,oracle都会增加parse count(total)统计值。

(2)若不存在相同sql,在获得 library cache锁存器后,从空闲列上查找最合适大小的空闲chunk。如果在获得shared pool锁存器过程中发生争用,则等待latch: shared pool事件。oracle会一直拥有shared pool锁存器,直到确保chunk为止。
(3)若不存在最适合大小的空闲chunk,则查找更大的空闲chunk后分割(split)使用,分割后剩下的内存区域重新登记到适当的空闲了。
(4)若检索了所有空闲列也没有找到恰当的空闲chunk,则检索LRU列。LRU列上的chunk是重建的,而且是当前不使用的(还没有pin的)。
(5)若在LRU列上检索也不能确保适当大小的chunk,则追加分配共享池内的剩余内存空间。
(6)如果以上过程失败,则发生错误ORA-4031。

(7)若找到合适的chunk,对sql相应的handle以Exclusive模式获得library cache lock,并创建LCO信息。创建LCO后,library cache lock变换为NULL模式,将library cache pin以Exclusive获得后,创建执行计划(execution plan)。第(2)~(7)号过程称为Hard parsing。如若发生Hard parsing,oracle将增加parse count(hard)统计值。若在Hard parsing过程中发现sql语句的错误,则parse count(hard)统计值和parse count(failure)统计值将会一起增加。

(8)oracle对sql cursor以shared模式获得library cache locklibrary cache pin,并执行sql。这个阶段称为执行阶段。sql cursor所参考的LCO,基本上与sql cursor相同的模式获得library cache lock和library cache pin。但是执行修改对象信息(如DDL语句)工作时,对相应的对象所对应的LCO以Exclusive模式获得library cache lock和library cache pin。
(9)oracle对执行结束的sql cursor fetch数据。这个过程就是fetch阶段。在fetch阶段里,sql cursor将library cache lock变化为null模式,并解除library cache pin。

parsing 阶段的cpu使用时间和执行parsing时经历时间记录在parse time cpu统计值和parse time elapsed统计值上。若在执行parsing过程中,为获得锁存器或TX锁等待时间拖长时,parse time elapsed统计值表现的比parse time cpu统计值高出许多。特别是多个会话同时执行hard parsing时,会出现parse time elapsed统计值大幅增加的现象,这是因为在获得大部分library cache锁存器或shared pool锁存器过程中发生争用,导致等待时间相应增加。
请注意:即便存在许多空闲chunk,但是只要未发现能承载最适合大小的理想空闲 chunk,oracle就不再执行工作。共享池的空闲内存(free memory)虽然很富裕,但还是会出现错误ORA-4031就是这个原因。这种现象大部分发生在过度hard parsing导致空闲chunk分割的时候,这种共享碎片化也影响shared pool锁存器争用。共享碎片化,则空闲列包含许多空闲chunk。为了分配空闲chunk检索空闲列的过程中,需要获得shared pool锁存器,所以chunk被分割得太碎,空闲列检索时间会增加,相应地拥有shared pool锁存器的时间也会增加。
发生错误ORA- 4031时,alter system flush shared_pool 命令作为应急措施使用,在共享池flush时,连续的空闲chunk会聚合,所以下次请求sql是发现相当大小的空闲chunk可能性提高。但是 shared pool的flush不是错误ORA-4031的解决方案,要知道flush也可能会引起其它性能问题。
每次发生parsing 时,均需要获得library cache锁存器,所以发生争用的概率特别高。library cache锁存器争用与系统性能有直接联系,所以oracle为了解决library cache锁存器争用提供了多种方法。第一,对于PL/SQL内反复执行的sql cursor时,只有在最初执行时parsing,之后没有soft parsing也可以执行。因为不发生soft parsing,所以也不获得library cache锁存器。oracle将sql cursor相应的LCO pin在SGA上,所以即便没有获得library cache锁存器也可以参考LCO。第二,提供在会话内部里缓存LCO位置的功能,这就是session cursor caching。oracle将一个会话内执行三次以上的sql cursor的位置和sql文本,存在到SGA,所存储的sql cursor数量由SESSION_CACHED_CURSORS参数决定。即便使用了次功能,也依然会发生soft parsing,需要获得library cache锁存器,但不用检索库高速缓存区结构,而直接找到LCO位置,所以能缩短获得library cache锁存器的时间,相应的library cache锁存器所引起的争用也会减少。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值