SHARED POOL 的设计就是为了语句共享减少解析,如果语句不共享那么SHARED POOL 越大越有害!

深入shared pool

 

 

解析SQL语句

生成执行计划

中间考虑的因素很多,包括访问的对象的存在、权限、等等

执行SQL语句

 

解析的过程(生成最优执行计划)是一个耗费资源的过程,随着用户的并发数量的增加。数据库的性能也会降低的很快。

 

ORCLE对解析的执行

1、ORACLE将SQL语句分成为两个部分:静态部分+动态部分

2、静态部分:SQL 语句的关键词(所涉及的表名称、列名称、等)

3、动态部分:字面值(表里面的表数据,例如 where name=‘xkj’中的xkj)

静态部分是有限的、动态部分是无限的

 

绑定变量:实现SQL共享(静态部分),减少解析。在实际中,不同的SQL语句的静态部分的重复率非常的高。实际上,动态部分对SQL语句的解析的影响可以忽略不计

通过使用绑定变量,用来提高SQL语句的缓存命中率(减少解析次数、减少sql缓存)

 

declare

v1 varchar2(10);

n1 int;

begin

n1:=1

       select salary into v1 from test where id=n1;

end;

 

在上面的SQL语句中,使用了绑定变量n1,在解析的时候,使用的绑定变量。执行的时候,将字面值传入语句中。因此这样SQL语句的命中率将会提高。

 

ORCLE将解析过的SQL语句缓存在shared pool中,碰到相同的SQL语句再次执行的时候,ORACLE直接使用已经解析过的执行计划。

         Shared pool缓存内容:SQL语句、执行计划、PL/SQL代码、PL/SQL机器码等

 

Shared pool细分

1、库缓存:最近执行的SQL语句、存储过程、函数、解析树、执行计划,最活跃部分

2、数据字典缓存:SQL执行过程中涉及的数据字典

递归调用:shared pool为生成执行计划,又进行了很多别的调用(如查询数据字典)

row cache 缓存数据字典信息,取消了递归调用

 

Shared Pool的内存结构(由许多的内存块组成,这些内存块称为chunk)

       1、chunk是shared pool中内存分配的最小单元(类似于extent)

       2、一个chunk在内存中是连续的

 

Chunk的分类

       1、free:chunk中没有有效的对象,可以不受限制的分配

              如果用于存放和SQL相关的数据,那么chunk就属于library cache,如果用于存放数据字典,那么这个chunk就属于dictionary cache

       2、recr:recreatable,chunk里面包含的对象可以被临时性的移   走,如果需要,可以重建,例如共享SQL语句

       3、freeabl:session用过这个trunk,里面存放的对象数据是session    在处理过程中产生的,没有办法重建,这点不同于recr。因此这个 trunk不能被临时性的移走。但是在合适的时间段可以被释放。

       4、perm:permanent,chunk中包含永久性的对象,但是大型的  permanent类型的chunk中可能包含可用空间,需要的时候,这些空       间可以被释放

 

Shared poolchunk的分配

1、shared pool中的chunk的大小是不一样的,但是肯定是连续的

2、因为chunk是分配的最小单元,因此session需要给对象分配空间的时候,会以chunk为单位进行申请

3、可用的chunk(free)会形成一个链表,便于进行分配的时候,可以通过遍历链表寻找到可用的适合的chunk,链表是chunk进行组织和管理的一种方式

4、一个可用的chunk链表是一个bucket,shared pool中会有很多的bucket,不同的bucket中的chunk的大小不同,一般是随着bucket编号的增加,bucket的大小是增长的

5、当需要从shared pool中寻找chunk的时候,首先会定位一个bucket,然后遍历bucket,寻找最合适的chunk

       如果chunk的空间比需要的空间大,那么这个chunk就拆分成两个,一个被分配、一个成为free,重新挂接到这个bucket上。

6、在寻找chunk的过程中,如果一个bucket中没有合适的chunk,接着寻找另外一个非空的bucket,如果所有的bucket中都没有合适的chunk,那么就从rec类型的链表中释放一部分的空间,为free,或将free做适当合并。

7、shared pool中所有类型的chunk都是以链表的方式进行管理的

 

关于shared pool有两个问题

1、shared pool latch的争用问题

2、ORA-4013错误

shared pool latch争用(出现了大量的小的free chunk)

    lache锁(对内存结构保护,很快):控制buckct是否能使用,一个lache控制一类buckct

    只有rec类型的chunk能够被释放空间,即使释放了空间,这些空间可能都不是连续的,都是一些很小的chunk,这样可能形成这样一种情况,shared pool中是大量的非常小的chunk,这样在寻找chunk的时候,也很难寻找到合适的trunk

    同时因为free chunk数量非常的多,因此在分配chunk的时候,就会占用大量的时间,因为对bucket进行扫描、管理、分配的时候,需要获得shared pool latch,在扫描free chunk的时候,占用太多的时间,自然会发生latch争用的情况,原因就是因为大量的小的free chunk的情况

    select addr,KSMCHSIZ,KSMCHCLE from x$ksmsp where KSMCHCLE=free;查看小chunk数量

 

 

在语句被解析后要放入shared pool 中但是shared pool 中没有空间是会报ORA-4031错误。其原因可能是:

1、  共享池设的空间太小

2、  SQL语句没有共享,造成被解析的语句过多占用空间大,自然会造成压力

3、  有大量的free空间但是都是零碎的空间,都不能被使用。

对于第二种原因就要解决语句共享问题,另外SQL       语句不共享会导致cpu负载很高

desc v$sql; --> SQL_TEXT 查看共享池所有被共享的语句(子游标信息)

select sql_text from v$sql order by sql_text;看是否开启sql共享

select sql_text from v$sqlarea (父游标信息)

select addr,KSMCHSIZ,KSMCHCLE from x$ksmsp where KSMCHCLE=free; 查看小chunk数量

alter system set cursor_sharing=force; 在解析字面之前强行转化城绑定变量(但要不能随便改)

很多的情况会导致SQL不被共享:

1、SQL文本大小写不一致

2、SQL语句的绑定变量的类型不一致

3、SQL涉及的对象属于不同的schema

4、SQL的优化器不一致:  添加了提示、修改了optimizer_mode参数等

 

解决方法:

1.应用端(JAVA可通过JDBC将字面值转为占位符) (严格要求开发人员使用绑定变量)但是商品化老的软件改代码几乎不可能

2.数据库端 有局限性  使用procedures、function>package存储在后台,让应用端直接调用

对于第三种原因(同稀疏表)就要shrink 对表进行收缩然后降高水位线(移动表中的行不影响生产但降高水位线一定会影响生产,所以要先将表锁住。锁住以后别人无法访问但有人访问时就锁不住)

 

优化怎么入手?

使用工具、日志和5大报告

工具:视图、日志、数据字典

五大报告:ADDM/AWR/ASH/STATSPACK/RPA

对于shared pool 要关心的只需要知道libary chache 共享的sql和执行计划

Library cache

 

用户提交SQL语句或者PL/SQL以后,在library cache中会生成一个可执行的对象

这个可执行对象叫做游标(不同于SQL语句中的游标),对于所有的进程来说,这些可执行对象是共享的

游标可以认为是sql+执行计划

句柄就是指向文件的一个指针,指向文件的物理地址

 

Hash 算法

Oracle在内部管理中大量的使用到了hash

1、使用hash的目的就是为了快速查找和定位

对数值进行hash运算,产生一个索引号,然后根据索引号将数值放置到相应的hash bucket中去,根据hash运算的法则,会产生多个索引号,每一个索引号对应一个hash bucket(一个数值列)。我们在寻找数值的时候,将搜寻的数值进行hash,产生一个索引号,那么这个数值一定在这个索引号对应的 hash bucket中,于是直接跳转到这个hash bucket中进行遍历。这样我们定位数据的时候,就能够大大的减少遍历的数量。

 

       库缓存中就是使用hash bucket来管理的

1.    首先根据shared_pool_size指定的尺寸来自动计算hash bucket的个数

2.    每个hash bucket后面都串联着多个句柄

句柄描述了library cache里面的对象的一些属性,包括名称、标记、指向对象所处的内存地址的指针

 

 

 

一条SQL语句被获取后在shared pool中解析的过程:

一条SQL语句进入à将SQL文本转化为ASCII值-à对ASCII等参数进行hash函数的运算-à得到一个数值、就是hash bucket的号码-à将对象句柄放进相应的hash bucket中去

进程要处理某个对象,例如一条SQL语句

首先对语句进行hash,得到一个编号-à进入hash bucket中进行扫描-à

1、该对象句柄存在,ok,直接使用

2、该对象句柄存在,对象被交换出内存、装载对象

3、句柄不存在,重新构建一个对象,挂在到hash bucket上

 

SQL的解析过程(硬解析和软解析)

用户识别的是SQL语句,oracle可以执行的是代码,这个转换过程叫做解析

解析分为硬解析和软解析,SQL语句第一次解析时必须进行硬解析

硬解析

1、客户端发出一条SQL语句,SQL语句进入共享池

       该SQL语句以及相关的辅助信息组成游标

2、对SQL语句进行hash运算,得到一个hash值,转入相应的bucket中去

3、对bucket进行遍历,查找是否存在这条SQL语句

4、如果不存在这条语句

       1、获得shared pool latch,然后在shared pool中进行chunk链条的遍历,找到合适的chunk,之后释放shared pool latch,chunk进入library cache中

       2、硬解析开始

硬解析过程:

1、对SQL语句进行语法的检查。如果有错误,那么就退出解析过程

2、到数据字典中校验SQL语句所涉及的对象和列是否存在,如果不存在,退出解析过程,这个过程会加载dictionary cache

3、对对象进行名称转换,同名词等要转换成实际的对象,转换失败就退出解析

4、检查发出SQL语句的用户是否具有访问sql语句里面所引用的对象的权限,无权限就退出解析过程

5、通过优化器创建一个最优的执行计划,这个过程会根据数据字典里面记录的对象的统计信息,来计算最优的执行计划,这一步涉及的运算量很大,最耗CPU资源

6、该游标所产生的执行计划、sql文本等装载进 library cache的heap中

在解析的过程中,进程会一直持有library cache latch,一直到硬解析结束

游标

1、硬解析结束以后,产生两个游标:       父游标和子游标

父游标里面包含的信息包括SQL文本和优化目标。

       session打开该游标以后,就会锁定父游标,所有的session都关闭该游标以后,锁定才能够释放

       父游标在被锁定的时候,不能被交换出内存

       父游标交换出内存、子游标也会被交换出内存

       子游标被交换出内存、父游标可以不被交换出内存

       因为一个父游标可能会有多个子游标

子游标包换所有的信息:执行计划、绑定变量等

       子游标随时可能被交换出内存

       Oracle根据父游标的信息可以构建出一个子游标,这个过程叫reload

 select 100*sum(reloads)/sum(pins) Reload_Ratio from v$librarycache

上面的语句确定reload的比率,我们希望低一些最好。

一般的情况是父游标不会被交换出内存,子游标会被交换出内存。

为什么会产生父游标和子游标呢?

1、一个父游标可以对应多个子游标

       子游标的个数可以从视图v$sqlarea中的version_count字段中体现出来

       每个具体的子游标则全部在视图v$sql中体现

产生子游标的一些情况举例

1、具体绑定变量的值与上次绑定变量得值有较大的差距

       例如上次是6位,现在是200位

2、sql语句完全相同,但是所引用的表属于不同的用户

等等

软解析

1、硬解析是一个完整的解析过程,如果解析过程中去掉一个或者多个步骤的话,这样的解析叫做软解析

2、在bucket中找到了sql语句,就会进行软解析,因为如果没有找到,那么说明这个语句是第一次执行,第一次执行肯定是硬解析

软解析的三种类型

1、某个session发出的SQL语句与library cache里其他session发出的SQL语句相同,解析可以省略5和6,但是2、3、4还是需要执行的

2、某个session发出的sql语句是这个session之前发出的曾经执行过的语句,那么2、3、5、6可以省略,但是4不能省略,因为中间可能发生过grant等操作

3、设置了初始化参数session_cached_cursors时,当某个session第三次执行相同的sql语句时,这个sql语句的游标信息会转移到该session的PGA中去,这样以后可以直接在session的PGA中寻找SQL,提高了效率,但是内存的消耗会很大

软解析省去的步骤:

1.    不需要获取shared pool lache (free)

2.    不需要生成执行计划

3.    不需要将生成的计划写到chunk中

Shared pool 的大小设置

1、不同的系统需要不同的值

2、不要太大、不要太小,无论大还是小,对性能都有影响

通用的方法是

1、设置一个初始值、让系统运行一段时间

       初始设置shared pool的大小是SGA的10%、不要超过1G

2、对shared pool的使用情况进行观察和监控

       9i以后,我们可以使用advisor进行监控,然后查询找到合适的值

3、得到一个比较合理的值

4、继续观察、根据负载情况的变化,需要相应的调整参数

5、shared pool不要设置1G以上

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值