深入解析Oracle学习笔记(第六章)

访问数据,首先确定数据是否在内存中,如果在,判断直接访问还是构造一致性读。如果不在,需要在buffer cache寻找足够的空间装载数据,如果空间不够,需要触发DBWR写出脏数据,释放buffer空间。


如何确定需要的数据在buffer中?  cache buffer chain
如果需要的数据不在buffer中,如何去buffer cache中快速寻找内存空间?  cache buffer LRU chain


通过几个链表进行内存管理,如LRU LIST,   DIRTY LIST。list上存放的是指向具体buffer的指针等信息。


8i开始为了实施增量检查点,增加了检查点队列,文件队列。(queue,不是list)
8i开始,异步DBWn的引入,现在关于各种list和queue更为精确的概念是工作集(WS  Working set)。
每个WS包含几个不同功能的list。每个list都通过Cache Buffer LRU CHAIN Latch保护。
当使用多个DBWR进程时,数据库会存在多个WS,同时当使用Buffer Cache多缓冲池技术(keep ,default,recycle)时,每个独立的缓冲池也会存在各自独立的WS。




数据库初始化时,所有的Buffer都被Hash到LRU List上管理。
一个Buffer要么在LRU List上,要么在Dirty List上。


检查队列负责按照数据块的修改顺序记录数据块,同时将RBA和数据块关联起来。这样在进行增量检查点时,数据库可以按照数据块修改的顺序将其写出,从而在恢复时根据写出数据块及其相关的RBA开始进行恢复。


在检查点触发时DBWR根据检查点队列写出,其他条件触发时,根据Dirty List写出。
检查点队列的内存在Shared Pool中分配。(不在Buffer Cache中)






在从数据文件读取数据块到Buffer Cache之前,Server进程会扫描LRU List寻找Free的Buffer,把扫描过程中发现的Dirty Buffer注册到Dirty List上。
Dirty Queue超过25%就会触发DBWn写操作(触发写操作的情况之一)
Server扫描LRU List超过40%仍未找到足够的free buffer,则触发DBWn写操作,释放内存空间。(free buffer wait)
由于增量检查点的引入,DBWn也会主动扫描LRU List,把发现的Dirty buffer注册到Dirty List和Checkpoint Queue。这个比例是25%。


Oracle 8i开始,LRU List和Dirty List分别增加了辅助List。
当数据库初始化时,Buffer首先存放在LRU辅助List上,Buffer被使用后移动到LRU主List上。这样当用户进程搜索Free Buffer时可以从LRU_AUX list开始,DBWR搜索Dirty Buffer可以从LRU_Main List开始,提高了搜索效率和数据库性能。


多缓冲池,每个缓冲池包含多个WS。


用于锁定LRU 的latch就是常见的Cache Buffer LRU Chain latch,有多个子latch。


------------
如果所有的buffer cache中的所有buffer都通过同一个结构管理,当需要确定某个block是不在buffer中时,需要遍历整个结构,性能会很低下。
于是oracle引入了bucket数据结构,将管理的所有buffer通过hash算法运算后放在不同的bucket中。这样众多的buffer被分不到一定数量的bucket中。
这样当用户需要在buffer中定位数据是否存在是,只需要通过同样的算法获取hash值,然后到相应的bucket中查找少量的buffer即可确定。
每个buffer存放的bucket由buffer的数据块地址运算决定。
在bucket内部,通过cache buffer chain(双向链表)将所有的buffer通过buffer headre联系起来。
buffer header存放的是对应数据块的信息,包括数据块的文件号,块号,状态等。
判断数据块是否在buffer中,只需要检查buffer header即可。


9i开始,对于cache buffer chain的只读访问,其latch可以共享。


每个hash bucket只存在一个cache buffer chain。
从8i开始,每个latch要管理多个bucket,从而使用少量latch管理更多bucket成为可能。
通过增加bucket,每个bucket上的buffer数量大大减少。
8i之前,每个latch管理一个bucket,8i开始,每个latch管理多个bucket,但由于每个bucket里buffer数量大大减少,latch的性能反而增加了。
每个latch管理多个cache buffer chain


x$bh   每个buffer在x$bh中都存在一条记录,记录了很多信息,包括该buffer缓存的数据块的表空间,数据文件,数据块号等信息。TCH字段代表该buffer被访问的次数。

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

oracle 7之前,shared pool不存在。

oracle引入shared pool是为了实现代码的共享与重用。

字典缓存的内容按行存储(row cache),其他数据通常按buffer存储。

v$librarycache    v$rowcache

从11g开始,除了字典缓存和库缓存,shared pool又增加了result cache(查询结果缓存),提升了性能。

可以在服务器端缓存结果集,也可以在客户端缓存结果集。

服务器端result cache memory由两部分组成:SQL Query result cache和PL/SQL Function result cache。

参数result_cache_mode控制服务端结果集缓存的模式。如果模式为MANUAL,需要加hint才会缓存结果集。

v$result_cache_objects   v$result_cache_memory   v$result_cache_statistics


shared pool通过free list管理内存块(chunk),free的内存块按照不同的size划分到不同的部分(bucket)。

oracle请求shared pool空间时,首先进入相应的bucket查找,找不到的话就转向下一个非空的bucket,获取第一个chunk,分割这个chunk,剩余的部分进入相应的bucket,进一步增加碎片。

随着内存块被不断分割,bucket列表开始变长。

由于不停的分割,每个bucket上的内存块越来越多,越来越碎小。

通常每个bucket上的chunk多于2000个,就被认为是碎片过多。碎片过多,是shared poo性能问题的主要原因。

碎片过多导致搜索free list时间过长。管理和搜索free list需要获得shared pool latch。被长时间占有。

9i之前shared pool latch只有一个。

增加了更多的bucket,并进一步细分bucket,使每个bucket中容纳的chunk数量大大减少,提高了查询效率。


9i开始,shared pool可以被分割为多个子缓冲池。同时提供多个latch。子缓冲池最多有7个。latch也增加到7个。子latch。

子缓冲池的引入虽然使oracle可以管理更大的shared pool,但也可能会导致各分区之间的协调问题,比如某个sub pool被过度使用,但其他sub pool却有很多空间。

从10g开始,允许内存请求在不同subpool之间切换,提高了请求成功的可能。(但问题仍然可能存在)

对单个subpool进行进一步的细分,缺省的会将单个子缓冲池分割为4个子分区进行管理。(可能是因为4颗CPU才分配一个subpool)


测试表明subpool大小为500m可能会带来更好的性能,所以从11g开始每个subpool至少为512M。


x$ksmsp 视图记录shared pool空间分配和使用情况。每行代表一个chunk。


大量硬解析会不断申请分配free的内存,不断产生碎片。


内存碎片增加是共享池性能下降的开始。


library cache由一个hash表组成,hash表是由hash bucket组成的数组。每个hash bucket都是包含library cache handle的双向列表。library cache handle指向library cache对象和一个引用列表。library cache对象进一步分为依赖表、字表和授权表等。


9i——11g   v$librarycache 视图 


sql解析过程,将sql文本转换成ASCII数值,通过hash函数计算hash值,再通过hash值再shared pool中寻找是否有相同的sql,如果没有则尝试获取shared pool latch,请求内存,存储该代码。


语法解析--------》语义解析(对象是否存在,用户权限,是否引用相同对象)


对比:

bucket——》  BH      ——》buffer

bucket——》  library cache handle   ——》library cache object等。


shared pool的主要问题就是碎片过多带来的性能影响。


ORA-04031  当尝试在共享池分配大块的连续内存失败(很多时候是由于碎片太多,而非真正的内存不足)时,oracle首先清除共享池中当前没使用的所有对象,是空闲块内存块合并。如果仍然没有足够大的单块内存可以满足需要,则产生ORA-04031错误。


v$sqlarea sql version count,  parse_calls , executions


oracle 绑定变量 peeking机制。只在第一次硬解析的时候生效,所以仍然可能存在问题。


8i中cursor_sharing 有两个取值:exact  精确匹配。force 强制使用绑定变量。

9i中cursor_sharing有了第三个参数 similar,指定oracle在存在柱状图时,对于不同的变量值,重新解析。有柱状图的时候,跟exact相同。没柱状图是,跟force相同。

但也可能导致version_count过高的bug。


大量的version_count可能导致数据库产生大量的 cursor:pin S wait on X。


强制刷新缓冲池alter system flush shared_pool


shared_pool_reserved_size  制定了保留的共享池空间,用于满足将来的大的连续的共享池空间请求。

当出现过多碎片,请求大块空间会导致大范围的查找并释放共享池内存来满足请求,由此可能带来较为严重的性能下降。

设置合适的shared_pool_reserved_size  结合shared_pool_reserved_min_alloc参数用来避免由此导致的性能下降。

缺省值 shared_pool  * 5%建议10%——20% 

v$shared_pool_reserved


dbms_shared_pool.keep



library cache lock 等待事件(handle)   解析锁,比pin更高级别的锁,在对象的handle上获得,pin一个对象之前,必须首先获得该handle的锁定。   null share exclusive。

library cache pin 等待事件(object)   以读取或改变对象内容为目的所加的短时锁,   null share exclusive。该等待事件出现时,通常说明该pin被其他用户非兼容模式持有。通常是发生在编译或者重新编译对象时。


shared pool latch和library cache latch是shared pool管理中最重要也是最常见的latch竞争。过度解析容易造成这个问题。

shared pool latch用于共享池中内存空间的分配和回收。

library cache latch用于保护cache在内存中的sql及执行计划等。需要向library cache中增加新的sql时需要获得该latch。

简化的sql执行过程:

(1)获得library cache latch根据hash value在library cache中查找是否存在可共享代码。存在则软解析,转向第(4)步。不存在则硬解析。

(2)释放library cache latch。获得shared pool latch,查找并锁定自由空间。

(3)释放shared pool latch,重新获得library cache latch,将sql及执行计划插入library cache中。

(4)释放library cache latch,保持null模式的library cache pin/lock。

(5)开始执行sql。


version_count过高通常会导致library cache latch长时间持有,从而影响性能。


v$session_longops  视图


v$sql   v$sqlarea

从10g开始,v$sqlarea不再是v$sql的聚合,而是去掉了v$sql中为执行过的子指针之后再聚合。


你可能感兴趣的:(深入解析Oracle学习笔记(第六章))