令DBA迷惑的共享池核心概念总结(一)

 我们知道shared _pool非常重要,在自动管理的环境情,可能会被其他的内存组件占用shared_pool的空间,shared_pool空间不够时会引发各种各样的问题。在自动管理内存的环境下也可以定义各种组件的大小,这时候的定义是表示一个组件的最小值。所以建议给shared_pool_size手动设置一个最小值,这样保证shared_pool不至于太小而引发的各种问题。初始大小设置为(memory_target*0.6)*0.4 .观察一段时间,再根据实际情况做部分修改。

共享池当前大小,在手动管理模式下查参数shared_pool_size,在自动管理时,查动态性能视图:
SQL> select COMPONENT,CURRENT_SIZE,USER_SPECIFIED_SIZE from $sga_dynamic_components;

SQL > select sum(bytes) from v$sgastat where pool='shared pool';

subpool

只有一个共享池,则latch争用会比较频繁,早期版本如果分配过大的共享池内存则管理成本上的负担很严重。因为搜索对象要持有latch,对象多则搜索时间长,相对的latch持有时间久就容易产生latch争用。所以引入了共享池多个子池的方式,类似于working set
Sharepool
最多可以有7个子池,即使采用多个子池也不能彻底解决latch:shared pool,根源基本都是硬解析造成的。
启用方式
1. CPU
数量
1-4 CPU's = 1 subpool
5-8 CPU's = 2 subpools
9-12 CPU's = 3 subpools


2.
内存大小
ASMM
AMM环境.根据sga_target,memory_target计算.
手动管理时.根据指定的shared_pool_size决定
.
9I
要求约128M一个subpool,10G要求约256M一个subpool,11G要求越512M一个
ubpool.

3. _kghdsidx_count
隐含参数来确定subpool数量,优先级最高。


:无论哪种修改方式影响subpool数量,都要重启实例才生效.
subpool
具体多少个,是在实例启动时根据上述方法计算得来的,不能动态改变。




SQL> select name,value,ISDEFAULT,DESCRIPTION from h$parameter where name='_kghdsidx_count';

NAME VALUE ISDEFAULT DESCRIPTION
---------------- ---------- --------- --------------------------------------------------
_kghdsidx_count 1 TRUE max kghdsidx count

share pool latchsubpool一对一关系,因此通过如下查询可以判断已经启用的subpool数量。

SQL>select name,gets from v$latch_children where name='shared pool';

通过调整(扩大)共享池大小或调整隐含参数来达到增加subpool的目的,具体如下:

SQL> alter system set SGA_target=4G;

SQL> alter system set memory_target=4G;

SQL> alter system set "_kghdsidx_count"=4 scope=spfile;

subpool缓解latch:shared pool的争用,即使采用多个子池也不能彻底解决latch:shared pool
根源基本都是硬解析造成的。
SQL> select name,addr,latch#,gets,misses from v$latch_children where name='shared pool';

free list & LRU

内存分配给shared_pool,被拆分成多组不同大小的chunk。这些chunk一部分被使用,一部分属于空闲的。空闲的chunk挂在free list上管理。使用的chunk挂在LRU链表上。这里的LRUbuffer_cache中的LRU过期算法决然不同分为recurrent 周期,transient 瞬时 9k=


free list
结构:

head header:
就是链表头.

chunk
chunk
shared pool分配的最小单元

类似数据文件中的block
通常所需的chunk都是小于4K,大于的会分配到保留区中去

相同大小的chunks被一个bucket所管理

 

chunk的类型
SQL> select distinct KSMCHCLS from x$ksmsp;

KSMCHCLS
--------
recr
freeabl
R-freea
perm
R-free
free

6 rows selected.


chunk
基本四类:
free
存在于free list上的
chunk.
新空间申请,优先从这里获得.随时可以被分配
.
perm (permanent)
分配给系统对象使用
chunk.
fixed table,fixed view
等系统对象
.
实例生存周期中一直会存在.不会被释放
.
recr (recreatable)
可以被别的对象重建的
chunk
可以在被其他对象需要时移走,并且在需要时重新创建
.
例如:对象失效后,再次使用的reload操作
.
通常也是一组freeable chunk的带头大哥
.
freeable
如果freeable为首的recr被覆盖,则这组freeable也可以随recr一起覆盖或转为
free
recr没有被覆盖时,freeable不可以释放
.

R-*
代表reserved空间中的chunk.意思和上面一致
.


bucket
因为每条SQL所申请的内存大小不一(因为SQL_TEXT不同)
所以为了加速定位符合所申请大小的chunk,chunk上层由bucket分组管理

bucket
是在实例启动时oracle分配好的.




H8SloBkqHPR3AAAAABJRU5ErkJggg==


shared
申请内存的流程

1.
获得shared pool latch,获得不到产生等待,等待事件 latch:shared pool
2.
搜索空闲空间

如果有恰好大小的chunk 直接使用
如果没有恰好大小的chunk则找比申请值大的chunk,此时会切割这个chunk
按申请大小来切割,多余的放到大小合适的bucket
,
切割后的chunk不一定回到原bucket
.
freelist
上的小chunk是不能合并的.即使他们是相邻的.因为合并的统筹操作过程代价高
.
这就是共享池碎片的原因.

3.如果没有空闲空间根据LRU算法开始搜索。 为了减少LRU链表中的对象,使之搜索更快

         oracle把共享池的LRU分为:

                   1.周期LRU链表(recurrent)

                            类似于buffer_cache的主LRU()

                   2.瞬时LRU链表(transient)

                            类似于buffer_cache的辅LRU()

硬解析后子游标的chunk放在LRU链表中的瞬时链表,出于可能以后不会被用到的想法。其后第一次软解析时(每个会话第一次都是软解析,这里说的是硬解析后的第一次软解析)   将用到的子游标chunk由瞬时LRU链表,移动到周期LRU   这次移动需要shared pool latch的几次持有。

如果shared pool latch争用基本可以定位就是硬解析问题.

    解决:

       1.绑定变量

       2.subpool

       3.转为手动管理SGA,自动管理过程中shared_pool_size加大,也会持有shared pool latch

       4.cursor_sharing来优化,但技术不成熟,可能会出现Bug

 

SQL解析及cursor

为了将用户写的可读的SQL文本转化为oracle认识的且可执行的语句,这个过程就叫做解析过程。

解析分为硬解析和软解析。当一句SQL第一次被执行时必须进行硬解析。

当客户端发出一条SQL语句(也可以是一个存储过程或者一个匿名PL/SQL块)进入shared pool

(注意,我们从前面已经知道,oracle对这些SQL不叫做SQL语句,而是称为游标(cursor)。因为oracle在处理SQL时,需要很多相关的辅助信息,这些辅助信息与SQL语句一起组成了游标),oracle首先将SQL文本转化为ASCII字符,然后根据hash函数计算其对应的hash值(hash_value)。根据计算出的hash值到library cache中找到对应的bucket,然后比较bucket里是否存在该SQL语句。

如果不存在,则需要按照我们前面所描述的,获得shared pool latch,然后在shared pool中的可用chunk链表(也就是bucket)上找到一个可用的chunk,然后释放shared pool latch。在获得了chunk以后,这块chunk就可以认为是进入了library cache。然后,进行硬解析过程。硬解析包括以下几个步骤:

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

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

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

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

5) 通过优化器创建一个最优的执行计划。这一步是最消耗CPU资源的。

6) 将该游标所产生的执行计划、SQL文本等装载进library cache的若干个heap中。

在硬解析的过程中,进程会一直持有library cach latch,直到硬解析结束。硬解析结束以后,会为该SQL产生两个游标,一个是父游标,另一个是子游标。父游标里主要包含两种信息:SQL文本以及优化目标(optimizer goal)。父游标在第一次打开时被锁定,直到其他所有的session都关闭该游标后才被解锁。

一个父游标下可以有多个子游标。有父子游标目的是为了SQL_ID相同时,要共享执行计划做软解析。但即使SQL_ID匹配也不见得能够共享执行计划。执行计划在子游标里存放,不能共享的原因很多,V$SQL_SHARED_CURSOR 视图会告诉我们不能共享的原因。

如何找到library cache里的子游标中的执行计划?  library cache的结构和buffer cache宏观结构很相似,对比如下:

 

Z

 

 

 

 

Y2Fmap3zNeAAAAAElFTkSuQmCC

 

cbc latch 对应 library cache latch

hash bucket 一致
BH
对应 library object handle
hash chain
对应
library object chain (LOC)
library object chain (LOC)其下的内容就不同了。具体如下下图所示:

2Q==

 

 

 

通过对shared pooldump来可以看到具体结构:

对共享池做dump:(可选)

对内存做个2050级别转储,这会把整个SHARED POOL转储出来.要提前将shared pool 缩小.

ALTER SESSION SET EVENTS 'immediate trace name heapdump level 2050';

library cachedump:

ALTER SESSION SET EVENTS 'immediate trace name library_cache level 16';

通过如下方法可以看到dump后的trace文件:

SYS@ora11g> conn / as sysdba

Connected.

SYS@ora11g> ALTER SESSION SET EVENTS 'immediate trace name library_cache level 16';

 

Session altered.

 

SYS@ora11g> select * from v$diag_info where name='Default Trace File';

通过如下SQL可以确定某SQL语句的如下信息:

SYS@ora11g> select KGLHDPAR,KGLHDADR,KGLOBHD0,KGLOBHD6,KGLNAOBJ from x$kglob
where KGLHDPAR=KGLHDADR and KGLNAOBJ='
SQL文本
' ;

x$kglob.KGLHDPAR=x$kglob.KGLHDADR 则是父游标句柄地址.
x$kglob.KGLHDPAR<>x$kglob.KGLHDADR
则是子游标句柄地址
.
x$kglob.KGLNAOBJ
是对象名,对应一个cursor就是
sql_text.
x$kglob.KGLOBHD0
是父/子游标heap0DS(描述符
)
x$kglob.KGLOBHD6
是子游标heap6DS(描述符
)

 

1.找到这条sql对应的父游标library object handle地址SYS@ora11g> select KGLHDPAR,KGLHDADR,KGLOBHD0,KGLOBHD6,KGLNAOBJ from x$kglob
where KGLHDPAR=KGLHDADR and KGLNAOBJ='
SQL文本' ;

2.library cache转储中查看父游标parent cursor handle:0000000067D30048
vim搜索方法 /\c67D30048

library cache lock
1 null
可破碎的解析锁

2 shared
3 exclusive

library cache pin
1 null
可破碎的解析锁
2 shared
3 exclusive

 

library cache中,多个session之间读写阻塞关系如下:
读读不阻塞
读阻塞写
写阻塞读

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/18841027/viewspace-1651667/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/18841027/viewspace-1651667/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值