是SGA的一个组件,共享池是为了让我们大家共享数据而设置的缓冲池。共享池的内存是通过Oracle 通用内存管理来进行管理。KGH heap Manager
所有共享池的free内存都被挂在成为freelists的空闲链表上,链表是按照bucket机制建立,更具空闲内存片段大小,挂在了不同的bucket上。
分配的内存是可释放的:freeable 或者 recreateable
其中 freeable 是可以直接释放的,而recreateable 的内存是在unpin之后释放。都是可以重用的内存
内部结构
采用堆管理的模式(HEAP)
堆管理的基础就是KGH。负责管理和维护共享池中的内存结构包括SQL语句、PL/SQL代码、执行计划等共享的数据库对象。
内存被划分为一系列大小不等的Memory Chunk。每个Memory Chuck 都有一个对应的Free List ,用于管理 Chunk 内的可用内存块。
子池设置的目的是为了提高共享池分配回收和管理的性能,加大共享池的并发访问能力,因此他的存在坑定能够提升共享池的性能,其次了解子池技术可能带来的负面影响,由于一个大的共享池会被分割为若干个较小的子池,每个子池独立管理Free List,因此采用子池后,每个子池的容量也就变小了,也就增加了共享池碎片化的可能性。
行缓冲(Row Cache )也叫做 字典缓冲,缓冲是以行为单位组织的。
字典缓存绝对不是纯粹的数据字典表的缓冲。数据字典表和普通的表没有不同,其数据块的缓冲也是相同的。而字典缓存是经过组织的,用于数据库运行中SQL解析,权限控制等用途的内部数据结构,是一种字典表的内存试图。如果Oracle在执行某个SQL的时候,为了SQL解析,需要访问一些字典表,从中获取一些数据,那么它会通过一些递归调用SQL来完成这些事。为了减少递归SQL的执行开销,这些行数据呗缓存在共享池中,这个缓存就是字典缓存。
库缓存和游标
库缓存是共享池的一个子堆
完整的游标包括一个父游标,并且至少包含一个子游标。
对于SQL 的文本做散列计算,会得到一个散列值,通过该散列值就可以找到相应的游标,由于散列值是根据游标名称的每个字符进行散列计算得到的。
每个父游标包含一个句柄KGLHD、一个对象结构KGLOB、一个或者多个名字结构KGLNA。KGLOB指向子堆
KGLHD是每个游标的入口。
游标与游标共享
可以提高共享池的使用效率,减少SQL解析的开销,从总体上提高SQL执行的效率。
判断游标共享:
1、可共享的游标SQL文本必须完全相同。首先对其文本激素那散列值,然后通过散列值在HASH Bucket 上查找。
2、两个SQL的执行计划不同,如果两个SQL相同,但是由于参数不同,必须使用不同的执行情况。
执行计划QEP
FETCH阶段:SELECT操作比普通的SQL多了一个FETCH步骤,实际的DB BLOCK的访问才会产生,将删除不需要的数据,把结果放入结果集,传输给客户端。
动态分配共享池空间,不需要因修改共享池参数而重启数据库实例。
《绑定变量窥探技术》
某条SQL一直执行正常,突然就很慢? 查看系统资源是否存在瓶颈,存在一些异常问题,出现换页、CPU资源不足、IO问题等。需要通过操作系统的监控工具进行分析。
select count(*),event from v$session_wait group by event order by count(*)
绑定变量对应的字段数据不是均匀分布,而是倾斜的,某些取值的数据量比较大,而另一些取值的数据量又比较小。
在RAC的不同节点上,相同的两个SQL执行计划不同。如果发现这条SQL中使用了绑定变量,并且绑定变量对应的字段值域也是倾斜的,那么绑定变量窥探导致这个问题可能性就十分高。在RAC环境下,SQL的执行计划是势力范围内,不会跨实例。如果两个实例解析这条SQL时,窥探到的绑定变量的值是不同的,那么可能会导致生成的执行计划也不同。
ACS 自适应游标共享
CURSOR_SPACE_FOR _TIME 参数(减少使用,一般不推荐):目的是为了减少游标所的数量,从而减少共享池的相关闩锁的争用。
原理:当父游标被开启的时候,所有的子游标及其关联的相关对象全部被锁住,从而确保该游标所有的相关信息都是一致的,并且是完全保证在共享池中,进而提高游标中兴是的效率,如果这个参数没有被设置,那只有当SQL处于执行阶段是。相关的对象才会被锁住。一旦执行阶段完成,就没必要在锁住整个游标了。
游标在执行完毕后斌不是物理关闭,而是放在游标高速缓存里,那这些游标就会锁住,无法被释放继续使用。直到会话退出,才会真正关闭这些游标,而直到最后一个使用游标的会话退出,该游标才能被换出。这样可能导致大量的共享池对象被锁住,是共享池碎片化,严重时导致共享池无法分配足够大小的连续空间,系统将出现故障,宕机。
SESSION_CACHED_CURSORS参数:软关闭的方式,使游标不被真正关闭,提高表单应用的效率。主要功能是将某个会话中常用的SQL放入UGA中的会话缓冲池里,以便下次调用,不需要再做解析,从而减少了共享池的争用。
exec :id = 1010;
select empno,ename from emp where empno = :id;
exec :id = 1011;
select empno,ename from emp where empno = :id;
CURSOR_SHARING和游标共享:
9i开始能够支持SIMILAR参数值,弥补force设置的不足对于存在柱状图的列,可以进行绑定窥探,从而解决了force产生的问题,这样既可以共享SQL,又不会产生交叉的执行计划。
游标共享算法:
既避免了类似CURSOR_SHARING=FORCE的执行计划不准去的问题,又避免了CURSOR_SHARING_SIMILAR的大量游标不能共享的问题。
解决方案就是11g中的ACS。在ACS启动时,绑定窥探技术得到了发挥,在判断游标是否可以共享的时候,会根据绑定变量的值进行分析。如果值域对应的选择性可以使用原有的执行计划,就共享SQL,否组就创建一个子游标。这种技术既解决了游标共享的问题,又有效避免了因绑定变量值不同而采取不同执行计划的问题。
还是又可能出现大量子游标的情况,应当立即关闭ACS,通过设置_optimizer_extended_cursur_sharing_rel=none
来关闭功能。
在12c版本中,cursir_sharing=similar
已被禁止使用,不在支持这个设置。
游标关闭
关闭游标分为软关闭和硬关闭,软关闭的游标虽然被客户端程序关闭了,但是实际上在游标缓冲区中,仍处于打开状态。只有当游标被硬关闭了,他和绘画之间的练习才会彻底断掉,将来这个会话要再次执行同一个SQL时,就需要重新创建游标的相关数据结构了。
互斥锁(mutex)和游标
是一种轻量级的同步锁机制,通过维护一个计数器和一个等待队列再实现互斥。
互斥锁是由KGX层面提供的,和闩类似,他也是采用操作系统的原子操作,以Compare And Swap(CAS)的方式来自旋获取相应的互斥锁。
shared_pool_size
shared_pool_reserved_size
shared_pool_rederved_min_alloc
cursor_sharing
open_cursors
session_cached_cursors
_kghdsidx_count
sga_target
共享池故障处理
分为共享池不足,碎片化,闩争用严重等几个方面
ORA-4031
在共享池中分配内存时,共享池无法满足分配需求,从而报错。
需要从alert log 和 trace文件开始,结合 awr/statspack 报告时十分必要的
select * from v$diag_info where name = 'Diag Trace' ;
分析原因:到底是由于共享池容量不足还是由于共享池碎片化。如果共享池的空闲内存数量很小,那么很可能是共享池容量不足导致,而如果空闲内存比较大,但还是会经常出现ORA-4031,那么共享池碎片化导致带问题的可能性就比较大了
因为共享池设置偏低导致的,那扩大共享池就是十分好的解决方案
如果主要是因为共享池碎片化导致的,那么减少子池的数量,以及调整使用保留池的最小分配内存参数(比如从默认的4400调整为4000)。
使用共享内存自动管理:
首先要确保SGA-TARGET的设置时充足的,甚至略高于系统最高负载。另外要设置共享池的最小值(设置SHARED_POOL-SIZE参数)这样才能确保SGA的效率不会因为SGA RESIZE而大幅度下降。
共享池响应速度下降
在AWR报告中查看:
@?/rdbms/admin/awrrpt.sql
执行
共享池相关闩锁的等待时间虽然不到20%,但是平均等待时间超过了200毫秒,而这些闩锁的正常等待时间应为几毫秒,这是什么原因造成的?
可能性最大的因素包括:共享池过小,共享池RESIZE操作,有人在编译重要的存储过程或者视图,碰到了bug。
共享内存自动管理或者内存自动管理中共享池RESIZE操作频繁出现导致类似问题的可能性很大,可以通过 v$SGA_RESIZE-OPS视图来进行诊断。
编辑
level 266的系统状态转出,发现session 61在等待一个library cache lock ,而这个library cache lock 正在被自己持有,这是典型的自死锁现象,杀掉这个session 61即可解决问题。
共享池优化的主要思路
首先是共享池本身的配置,其次是游标的共享,然后是缓解共享池的碎片,最后是分析bug和补丁。
共享池的配置主要是看共享池的容量是否足够
共享游标可以减少大量的共享池空间,减少共享池中游标的总是两,从而减少共享池的争用,通过绑定变量和良好的SQL书写风格可以增加游标的共享。如果程序未使用绑定变量,可以通过将CURSOR_SHARING 参数设置为FORCE或者SIMILAR来加强游标的共享。
从10g版本开始,共享内存自动管理的引入,只要设置足够大的SGA-TARGET参数,共享内存就可以被Oracle自动管理了,在某些情况下,如果SGA_TARGET不足,共享内尊可能出现抖动,从而造成严重的共享池问题,还需要设置共享池的SHARED_POOL_SIZE参数,通过该参数,设置共享池的最小值,将这个值设置的足够大,可以确保共享池不会犹豫SGA抖动而出现严重的性能问题。