• 共享内存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

  • 相关阅读:
    notifyDataSetChanged() 现在不建议用了,删除的时候会导致position不变,导致删除这边,却删除的另一条
    android11 应用未安装:软件包似乎无效
    android room Schema export directory is not provided to the annotation processor so we cannot export the schema.
    git Ignore如何还原、脱离了git,如何连接
    android.enableJetifier 解决包duplicate
    875. 爱吃香蕉的珂珂 (二分应用)
    238. 除自身以外数组的乘积 (前缀和)
    1288. 删除被覆盖区间
    312. 戳气球 (分治、区间 dp)
    988. 从叶结点开始的最小字符串
  • 原文地址:https://www.cnblogs.com/polestar/p/4363095.html
Copyright © 2020-2023  润新知