Shared pool

一、Shared pool的引入

当你发出一条sql语句交付Oracle,在执行和获取结果前,Oracle对此sql将进行几个步骤的处理过程:

1、语法检查(syntax check)
       检查此sql的拼写是否语法。
2、语义检查(semantic check)
    诸如检查sql语句中的访问对象是否存在及该用户是否具备相应的权限。
3、对sql语句进行解析(prase)
    利用内部算法对sql进行解析,生成解析树(parse tree)及执行计划(execution plan)。
4、执行sql,返回结果(execute and return)

Oracle早期版本,并不存在shared pool,每次sql执行时,都会对sql进行以上解析执行操作。但是,在第三步解析、生成执行计划的过程中,开销非常昂贵,所以,oracle引入shared pool。

当一条sql语句到达数据库时,Oracle利用内部的hash算法来取得该sql的hash值,然后在library cache里查找是否存在该hash值; 假设存在,则将此sql与cache中的进行比较;
假设"相同",就将利用已有的解析树与执行计划,而省略了优化器的相关工作。这也就是软解析的过程。 如果hash值不存在,需要到Free空间中,找到相应大小的内存块,进行创建解析树、生成执行计划的动作。这个过程就叫硬解析。 创建解析树、生成执行计划对于sql的执行来说是开销昂贵的动作,所以,应当极力避免硬解析,尽量使用软解析。 这就是在很多项目中,倡导开发设计人员对功能相同的代码要努力保持代码的一致性,以及要在程序中多使用绑定变量的原因。

Shared Pool最初被引入的目的,也就是它的本质功能在于实现共享。如果sql没有共享,有shared pool不如没有。因为保存代码、执行计划等期待重用,有一定的系统开销,并且客户端要不停的获取Latch,试图寻找共享代码。如果没有sql及执行计划的共享,这种开销会成为ORACLE的负担。

二、Shared Pool的组成

Shared Pool主要由三部分组成,一部分是库缓存(Library Cahce),另一部分是数据字典缓存(Data Dictionary Cache),在ORACLE中也叫ROW Cache,最后一部分,Free空间。

Library Cache主要用于存储SQL语句、SQL语句相关的解析树、执行计划、PL/SQL程序块(包括匿名程序块、存储过程、包、函数等)以及它们转换后能够被Oracle执行的代码等。由于Library Cache在解析的过程,需要频繁的访问到数据库的字典信息,如表结构,表行数等,所以,将字典值缓存也放到shared pool中。字典缓存的内容是按行(Row)存储的(其他数据通常按Buffer存储),所以又被称为Row Cache。Free空间,为一个个小的内存块,使用chain连接起来。

shared pool从物理结构上来看,是由许多内存块组成。这些内存块称之为chunk。 Chunk是shared pool中内存的最小单位。 Chunk中所有的内存都是连续的。

在shared pool中可用的chunk会串起来成为可用链(free list),也称之为bucket.可用的bucket,被分为254个。当一个进程需要shared pool里的一个chunk时,该进程首先会在符合所需空间的bucket上扫描,找到一个合适的chunk。如果找的chunk尺寸比需要的尺寸要大,该chunk就会被拆分成2个chunk,一个chunk用来存放数据,一个则成为free类型的chunk并被挂在当前的该bucket。

如果当前bucket上没有符合chunk,就会从下一个非空bucket里找,所里的bucket都不符合,就会扫描已经使用的recreatable类型的chunk的链表。从该链表上释放一部分的chunk.

当shared pool找不到足够大小的所需内存的时候,就会发出ora-4031的错误信息。当我们查询v$sgastat里的可用空间时,可能发现name 为free memory可用空间还足够大,但是还是报错,是因为在发出ora-4031错误的时候,已经释放不少内存。但是在这些内存当中的chunk,没有一个chunk可以提供连续的的物理内存满足所需要的空间。

三、Shared Pool 相关概念

(1)CHAIN 链

串接内存块(),方便遍历。Oracle内存结构中,最大的特征,就是使用了大量的Chain链,使用锁(Latch)对链进行保护。

(2)chunk 内存块

(3)Free空间的内存结构

Free空间 ,由许多chain组成,这些chain根据内存块chunk的大小,进行串接,当需要使用时,可以遍历到合适的内存块,放入sql及执行计划,然后挂到Library Cache的chain上。

(4)Library Cache中的内存结构

Library Cache的chain,是按照sql语句的hash值来串接的,如果一个sql到oracle中执行,会首先算出这个sql的hash值,再根据这个值,来Library Cache中查找是否有对应的内存块,有,就是软解析,没有,则需要硬解析。

(5)x$ksmsp 视图

Shared pool每一个chunk,都在这个表中,有一条记录。

四、ORA-4031经典错误

产生的原因

ORA-4031错误的原因,一般是大量的hard parse导致了shared pool中的free list中产生大量的内存小碎片,当一个需要很大内存来进行hard parse的sql语句到来时,无法从free list中找到内存,即使进行内存的释放,还是不能找到符合的内存块。从而报ORA-4031错误。

解决办法

(1)Alter system flush shared_pool;治标不治本的解决4031错误。之后一段时间,大量存在硬解析。

(2)减少硬解析,是解决问题的关键。在前台调用时,采用绑定变量的方式,来减少硬解析。查询执行1次的sql语句,很有可能就是硬解析的sql。需要优化。

(3)保留区:当sql需要的chunk非常大时,不去Free空间找chunk,直接从保留区找空间。把保留区的空间设置大一点,避免4031错误。

五、Shared Cursor

Oracle里的cursor分为两种:一种是shared cursor,一种是session cursor。shared cursor就是指缓存在library cache里的一种library cache object,说白了就是指缓存在library cache里的sql和匿名pl/sql。当一条sql第一次被执行的时候,会同时产生parent cursor和child cursor,parent cursor的library cache object handle的heap 0里会存储其child cursor的地址,这个sql的执行计划会存储在上述child cursor的library cache object handle的heap 中,第一次执行上述sql所产生的parent cursor和child cursor的过程也就是所谓的"硬解析"主要做的事情。如果上述sql再次执行,Oracle只需要去扫描相应的library cache object handle,找到上次硬解析后产生的child cursor,把里面的parse tree和执行计划直接拿过用就可以了,这就是所谓的"软解析"。

六、Shared pool大小设置

shared pool是不是越大越好?答案是否定的。第一、当sql和执行计划没有实现共享的时候,ORACLE会因为有shared pool 的存在,而增加很多系统开销。这个时候,shared pool有等于没有。第二,如果shared pool设置很大,那么对应的Library Cache也会很大, cahce中的chain也会很大。当chain进行便来的时候,chain就会经常锁住,导致系统运行缓慢。在oracle 10g之前,shared pool大小一般不允许超过1g。但是,10g之后,引入了sub sharedpool的概念,sub shared pool多了之后,能保证chain不会过大,导致大量的锁,这样,shared pool能设置很大。

七、ROW Cahce

dictionary cache存放了在执行SQL语句过程中,所参照的数据字典的信息,包括SQL语句所涉及的表名、表的列、权限信息等。dictionary cache也叫做row cache,因为这里面的信息都是以数据行的形式存放的,而不是以数据块的形式存放的。对于dictionary cache来说,oracle倾向于将它们一直缓存在shared pool里,不会将它们交换出内存。

当一条SQL语句进入Library Cache时,oracle会到dictionary cache中找与操作对象有关的字典信息, 比如表明、表的列、用户权限等信息,如果dictionary cache中没有这些信息,将system表空间里的数据字典信息调入buffer cache内存,读取内存数据块的数据字典内容,然后将这些读取出来的数据字典内容按照行的形式加入dictionary cache里,从而构造出dc_tables之类的对象,然后从dictionary cache中的行数据中读取有关的列信息放入library cache中。

八、Library Cache

当一条 SQL 语句进入library cache 的时候,先将 SQL 文本转化为对应ASCII数值,然后对该这些ASCII数值进行 hash 函数的运算,传入函数的是SQL语句的名称以及命名空间。运用hash函数后得到一个值,该值是hash bucket的号码,从而该SQL语句被分配到该号的hash bucket里去。实际上,hash bucket就是通过串连起来的对象句柄才体现出来的,它本身是一个逻辑上的概念,是一个逻辑组,而不像对象是一个具体的实体。oracle根据shared_pool_size所指定的shared pool尺寸自动计算hash buckets的个数,shared pool越大,则可以挂载的对象句柄就越多。当某个进程需要处理某个对象时,比如处理一条新进入的SQL语句时,它会对该SQL语句应用hash函数算法,以决定其所在的hash bucket的编号,然后进入该hash bucket进行扫描并比较。有可能会发生该对象的句柄存在,但是句柄所指向的对象已经被交换出内存的情况出现。这时对应的对象必须被再次装载(reload)。也可能该对象的句柄都不存在,这时进程必须重新构建一个对象句柄挂到hash bucket上,然后再重新装载对象。SQL语句相关的对象有很多(最直观的就是SQL语句的文本),这些对象都存放在library cache里,它们都通过句柄来访问。可以把 library cache理解为一本书,而SQL 语句的对象就是书中的页,而句柄就是目录,通过目录可以快速定位到指定内容的页。

Library cache lock/pin

Library cache lock/pin是用来控制对library cache object的并发访问的。Lock管理并发,pin管理一致性,lock是针对于library cache handle,而pin是针对于heap。

当我们想要访问某个library cache object,我们首先要获得这个指向这个object的handle的lock,获得这个lock之后我们就需要pin住指向这个object的heap。

当我们对包,存储过程,函数,视图进行编译的时候,Oracle就会在这些对象的handle上面首先获得一个library cache lock,然后再在这些对象的heap上获得pin,这样就能保证在编译的时候其它进程不会来更改这些对象的定义,或者将对象删除。

当一个session对SQL语句进行硬解析的时候,这个session就必须获得library cache lock,这样其他session就不能够访问或者更改这个SQL所引用的对象。如果这个等待事件花了很长时间,通常表明共享池太小(由于共享池太小,需要搜索free的chunk,或者将某些可以被移出的object page out,这样要花很长时间),当然了,也有可能另外的session正在对object进行修改(比如split 分区),而当前session需要引用那个table,那么这种情况下我们必须等另外的session进行完毕。

Library Cache lock有3中模式:

l  Share(S):     当读取一个library cache object的时候获得

l  Exclusive(X): 当创建/修改一个library cache object的时候获得

l  Null(N):     用来确保对象依赖性

比如一个进程想要编译某个视图,那么就会获得一个共享锁,如果我们要create/drop/alter某个对象,那么就会获得exclusive lock。Null锁非常特殊,我们在任何可以执行的对象(cursor,function)上面都拥有NULL锁,我们可以随时打破这个NULL锁,当这个NULL锁被打破了,就表示这个对象被更改了,需要从新编译。NULL锁主要的目的就是标记某个对象是否有效。比如一个SQL语句在解析的时候获得了NULL 锁,如果这个SQL的对象一直在共享池中,那么这个NULL锁就会一直存在下去,当这个SQL语句所引用的表被修改之后,这个NULL锁就被打破了,因为修改这个SQL语句的时候会获得Exclusive 锁,

由于NULL锁被打破了,下次执行这个SQL的时候就需要从新编译。

 

九、关注点

(1)软解析的命中率:

Labrary Cache需要在99%以上。

SQL> desc v$librarycache
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 NAMESPACE                                          VARCHAR2(15) 
 GETS                                               NUMBER  可以理解为某个object解析的时候查找的次数(解析阶段)
 GETHITS                                            NUMBER get命中次数
 GETHITRATIO                                        NUMBER 这个值等于gethits/gets
 PINS                                               NUMBER   某个object 解析过后被执行的次数(发生在执行阶段)
 PINHITS                                            NUMBER  pin命中次数
 PINHITRATIO                                        NUMBER  这个值等于pinhits/pins
 RELOADS                                            NUMBER 某个object 解析过后被从新加载的次数(需要从新从磁盘读取object),也就是没有被缓存到library cache中,这个通常由于shared pool 过小
 INVALIDATIONS                                      NUMBER 某个对象无效,通常由于对象定义被更改,需要从新解析

Shared pool的更多相关文章

  1. [转载】——故障排除:Shared Pool优化和Library Cache Latch冲突优化 (文档 ID 1523934.1)

    原文链接:https://support.oracle.com/epmos/faces/DocumentDisplay?_adf.ctrlstate=23w4l35u5_4&id=152393 ...

  2. 共享池之六:shared pool latch/ library cache latch /lock pin 简介

    latch:library cache --desc v$librarycache; latch:library cache用于保护hash bucket.library cache lock保护HA ...

  3. 共享内存shared pool (6):追踪sql语句

    构建实验数据 --使用NC50用户查询(会话1) SQL> conn NC50/NC50 Connected. SQL> create table emp as select * from ...

  4. 共享内存shared pool (5):详解一条SQL在library cache中解析

    前面介绍的 shared pool,library cache结构,都是为了说明一条SQL是如何被解析的.先看下面的图: 图中涉及的各结构简单介绍 父HANDLE,里面有父游标堆0的地址.. 父游标堆 ...

  5. 共享内存shared pool (3):Library cache

    Shared pool物理层面上由许多内存块(chunck)组成.从逻辑功能划分,Shared pool主要由三部分组成:Library cache,Dictionary cache和Control ...

  6. 深入理解shared pool共享池之library cache的library cache lock系列四

    本文了解下等待事件library cache lock,进一步理解library cache,之前的文章请见:  深入理解shared pool共享池之library cache的library ca ...

  7. 深入理解shared pool共享池之library cache系列二

    背景 继续上文:深入理解shared pool共享池之library cache系列一,学习library cache数据结构,本文主要学习library cache object(lco)的数据结构 ...

  8. shared pool详解

    共享池shared pool的概念用户提交的命令:解析.执行用户命令的解析解析的过程是一个相当复杂的过程,它要考虑各种可能的异常情况比如SQL语句涉及到的对象不存在.提交的用户没有权限等等而且还需要考 ...

  9. 【每日一摩斯】-Shared Pool优化和Library Cache Latch冲突优化 (1523934.1)-系列3

    减轻Shared Pool负载 Parse一次并执行多次        在OLTP类型的应用中,最好的方法是只让一个语句被解析一次,然后保持这个cursor的打开状态,在需要的时候重复执行它.这样做的 ...

随机推荐

  1. cocos2dx常见的46中+22中动作详解

    cocos2dx常见的46中+22中动作详解 分类: iOS2013-10-16 00:44 1429人阅读 评论(0) 收藏 举报 bool HelloWorld::init(){    ///// ...

  2. [转]http://lua-users.org/wiki/LpegTutorial

    Simple Matching LPeg is a powerful notation for matching text data, which is more capable than Lua s ...

  3. (实用篇)jQuery+PHP+MySQL实现二级联动下拉菜单

    二级联动下拉菜单选择应用在在很多地方,比如说省市下拉联动,商品大小类下拉选择联动.本文将通过实例讲解使用jQuery+PHP+MySQL来实现大小分类二级下拉联动效果. 先看下效果 大类:  前端技术 ...

  4. MongoDB学习笔记一:入门

    文档:多个键及其关联的值『有序』地放置在一起. {"greeting" : "Hello, world!", "foo" : 3}集合:一组 ...

  5. 5天玩转C#并行和多线程编程

    5天玩转C#并行和多线程编程系列文章目录 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq 5天玩转C#并行和多线程编 ...

  6. MySQL性能优化总结(转)https://yq.aliyun.com/articles/24249

    摘要: 一.MySQL的主要适用场景 1.Web网站系统 2.日志记录系统 3.数据仓库系统 4.嵌入式系统 二.MySQL架构图:   三.MySQL存储引擎概述 1)MyISAM存储引擎 MyIS ...

  7. knockout 学习实例5 style

    <!DOCTYPE html><html><head> <meta charset="utf-8"> <title>&l ...

  8. oracle返回多个参数

    CREATE OR REPLACE PACKAGE BODY get_form_no_pub IS /*================================================ ...

  9. android学习笔记56——Service

    Service四大组件之一,需要在AndroidMainfest.xml中添加相关配置,运行于后台,不与用户进行交换,没有UI... 配置时可通过<intent-filter.../>元素 ...

  10. 【freemaker】之文本,html文本,去除空格,字母大小写,循环数组,字符串截取,map取值,遍历map

    测试代码 @Test public void test06(){ try { root.put("emp", "<span color='red'>你好张三& ...