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


      前面介绍的 shared pool,library cache结构,都是为了说明一条SQL是如何被解析的。先看下面的图:

    图中涉及的各结构简单介绍

    • 父HANDLE,里面有父游标堆0的地址。。
    • 父游标堆0:有指向一个或多个子游标的HANDLE的句柄地址
    • 父游标在第一次打开时被锁定,直到其他所有的session都关闭该游标后才被解锁。当父游标被锁定的时候是不能被交换出librarycache的,只有在解锁以后才能被交换出library cache。父游标被交换出内存时父游标对应的所有子游标也被交换出library cache。
    • 子游标的HANDLE:有子游标堆0地址
    • 子游标堆0:有SQL语句依赖关系,并指向子游标的堆6
    • 子游标堆6:存有SQL语句的执行计划
    • 子游标随时可以被交换出library cache。当子游标被交换出library cache时,oracle可以利用父游标的信息重新构建出一个子游标出来,这个过程叫做reload(重载)。

    SQL语句在Library cache执行的第一次检查过程:

    1. 通过语法语义权限等检查的SQL语句进入Library cache
    2. 将SQL文本转化为ASCII值(大小写ASCII不同)并进行hash函数的运算
    3. 得到一个HASH值对应到hash bucket的号码

    ################以上检查通过后,进入以下解析过程################

    软软解析

      就是SQL执行3次,被缓存。第四次,就是软软解析了(不做详细论述)

    ####################################################

    软解析

    1. 获得library cache Latch ---如未获得将产生:Latch:library cache2.获得library cache lock,检索bucket上的父游标handle,得到所指向的父游标堆0-LCO的内存地址。
    2. 获得library cache pin,读取父游标堆0-LCO,得到子游标handle地址。
    3. 获得library cache lock,检索子游标handle,得到所指向的子游标堆0-子LCO的内存地址。
    4. 获得library cache pin,读取子游标堆0-子LCO从而得到子游标堆6地址。
    5. 读取子游标堆6,得到SQL执行计划。

    ###找到child lco后,增加parsecount(total)统计值。

    1. SQL开始执行:此时以共享模式获得library cache lock和library cache pin,并执行SQL。
    2. FETCH阶段:执行完成进入FETCH阶段,SQLCURSOR将library cache lock转换为null模式,释放library cache pin。

    ###############################################################

    在尝试软解析时

    --如果未检索到相同的父游标LCO或子游标LCO时,发生硬解析。

    --如果子游标堆6上不能加共享library cachepin或者child lco中信息不完整,需要重建执行计划--记录为硬解析。

    ###############################################################

    硬解析:

      如果未检索到相同的父游标LCO或子游标LCO时,发生硬解析。进程会一直持有library cache latch,直到硬解析结束为止。

    1. 获取shared pool latch,从freelist的bucket上查找合适大小的CHUNK。不存在大小合适的CHUNK会分割大CHUNK,剩余的会再进入相应的BUCKET。如果不能从free list的bucket上查找到合适大小的CHUNK,则进入 lru list;如果仍不能获取到CHUNK,则从shared pool剩余内在中分配。如果CURSOR达到_shared_pool_reserved_min_alloc隐含参数的大小标准(11.2.0.4中是4400),则从保留池中分配CHUNK;如 果这些分配CHUNK操作都失败,报错:ORA-04031。如bucket列表过长或者碎片严重,产生latch:shared pool争用。
    2. 分配到CHUNK后。获得library cachelock--独占模式,创建父游标handle
    3. 获得library cache pin,创建父游标堆0-父LCO的信息。--library cache lock转为NULL
    4. 获得library cache lock,创建子游标handle
    5. 获得library cache pin,创建子游标堆0-子LCO的信息。
    6. library cache pin,创建子游标堆6-执行计划的信息(通过优化器创建一个最优的执行计划,这个过程会根据数据字典里面记录的对象的统计信息,来计算最优的执行计划,这一步涉及的运算量很大,最耗CPU资源)。
    7. SQL开始执行:此时以共享模式获得library cache lock和library cache pin,并执行SQL。
    8. FETCH阶段:执行完成进入FETCH阶段,SQLCURSOR将library cache lock转换为null模式,释放library cache pin。

    关于MUTEX与图中librarycache Latch/PIN/LOCK的对应

    关于MUTEX,可以简单的把library cache Latch/PIN/LOCK当做MUTEX的不同模式来套入此步骤。
    在10G中,Mutex主要保护 handle和LCO---替代library cache PIN/LOCK
    在11G中,Mutex可以保护bufket上链表,handle和LCO---替代library cache Latch/PIN/LOCK
    句柄上访问竞争:Cursor:mutex   堆的访问竞争:Cursor:pin
    解析时MUTEX的相关争用
    相关锁
    (1)、计算HASH值,找到Bucket,搜索HASH链表,查找句柄。
        LIbrary Cache Latch(11G后被Mutex取代)
    (2)、在父游标句柄中查找父游标堆0
        mutex(取代Library cache lock latch) ,Library cache lock
    (3)、在父游标堆0中,查找子游标句柄。
         两次mutex。两种类型的Mutex。取代了Librarycache pin latch和Library cache pin 。
    (4)、在子游标句柄中,查找子游标堆0地址。
        mutex(取代Library cache lock latch) ,Library cachelock     
    (5)、在子游标堆0中,查找子游标堆6地址。
         一次mutex。取代了Librarycache pin latch和Library cache pin 。
    (6)、在子游标堆6中,读取SQL执行计划。
         一次mutex。取代了Librarycache pin latch和Library cache pin 。

    参考blog:

    http://blog.csdn.net/haibusuanyun/article/details/21402787

  • 相关阅读:
    KlayGE 4.0功能规划
    Kinect for Windows SDK发布
    CENTOS下用syslogng集中管理日志并压缩保存
    Eclipse+Plugin
    struts2 获取request、session的方法
    ActiveMQ使用经验
    springmock + dbutil 用来测试数据库操作
    英语学习
    如何查看eclipse版本
    jQuery插件的开发
  • 原文地址:https://www.cnblogs.com/polestar/p/4363095.html
Copyright © 2020-2023  润新知