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各内存结构的大小


[sql] view plain copy print ?


1. SQL> select * from v$sgastat where
2.   
3. POOL         NAME
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
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语句中的值(即表里的数据)。

共享池 java 共享池房源流转顺序_共享池 java


从上面这个图中可以看到,当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.


[sql] view plain copy print ?

    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. '.trc'
    7. from (select
    8. from
    9. where
    10. and
    11. and
    12. select
    13. from
    14. where v.name = 'thread'
    15. and (v.value = 0 or
    16. 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”部分:


    [sql] view plain copy print ?

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


    共享池 java 共享池房源流转顺序_library_02

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


    [sql] view plain copy print ?

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


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


    [sql] view plain copy print ?

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


     

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

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

    共享池 java 共享池房源流转顺序_parsing_03

    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 lock和library 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锁存器所引起的争用也会减少。