19、解析2_1(链、chunk、锁)

解析

shared pool

图解:

library cache里面,暂时可以认为存储着:

1、SQL以及对应的执行计划(所占空间比较小);

2、存储过程、函数、触发器、包,它们编译后的对象(所占空间往往比较大,特别是包所占的比较大)

对于shared pool管理和研究的时候,row cache一般不会出现问题,所以一般情况我们都不研究row cache,会出问题的经常是library cache,所以我们经常研究它

如果要执行包里面的一个存储过程的时候,oracle就会把整个包头(包规范)的部分调到library cache里面去,这时候就可能造成比较大的一个对象突然被调到library cache里去,这时候有可能会报4013错误;所以写包的时候,尽量不要把过多的存储过程或者函数放到一个包里面去

在shared pool里,有时候可能造成比较大的一个对象突然被调到library cache里去,这时候有可能会报4013错误,所以为shared pool专门设了一个,一个比较大的对象突然被调到library cache里去的空间:reserved空间,用来存储突然来的大对象的空间,占shared pool空间大小的5%,

假设library cache的大小为5G,缓存着大量的SQL以及SQL的执行计划,现在,要去执行一个SQL,就在library cache里面的这些大量的SQL以及SQL的执行计划里面找,这就有一个问题,该怎么找呢?假设library cache里面有100万行,然后一个一个去对比,就要找100万次,这显然就不合适;

管理SQL以及SQL的执行计划

链(chain)

那么library cache里面是如何组织和管理SQL以及SQL的执行计划的,以便于很方便的找到要执行的SQL?

图解:

用链把一个一个的SQL链起来,假设library cache有500M大小,用4个链来管理SQL;对于SQL1来说:SQL1经过hash以后,得到hash值,然后计算:hash值/4的余数(0、1、2、3......):如果余数 = 0,就把SQL1挂在0号链上;如果SQL1在library cache里面,server process就认为SQL1一定在0号链上,然后在0号链上找,不需要在另外的链上找;另外假设SQL2,经过hash,然后计算余数,假设余数 = 1,就在1号链上找,最终没有找到,它就不找了,因为也不可能在其他的链上,然后SQL2就要产生硬解析了

链的特点:

1、链的一种访问方式:只能遍历,不能随机访问(找到链的头部就可以一个一个的找,一直找到链的尾部)

2、一种链一种作用(比如SQL经过hash,然后挂在链上的,找的时候也是SQL经过hash然后在链上找)

library cache里面的链:就是SQL经过hash值的方式挂起来的(当初怎么组织的,找的时候就怎么找)

library cache的大小,会影响链的数量(library cache多大,链的数量是多少,这个是oracle自己去调整、适应的;我们也可以调整相关的参数来调整链的数量)

一个链可以认为是一个bucket(桶)

Hash(其实就是一个函数)

例如对于SQL:select name from t where id = :x;

oracle会把SQL语句里面的每一个字母,转换成一个ASCII码值,每一个字母对应着一个编码,

一个SQL --> 一堆的文本字母 --> 一堆的数字

hash值与SQL的几种对应关系:

1、如果SQL1和SQL2完全相同,那么它们的hash值一定相等

2、如果SQL1和SQL2不相同,那么它们的hash值一定不相等

3、如果SQL1和SQL2的hash值相等,但是SQL1和SQL2不一定相同

所以比较两个SQL时:

1、如果两个SQL的hash值不相等,那么两个SQL就不相;

2、如果两个SQL的hash值相等,那么还要比较两个SQL,一个字母一个字母的去比较

free空间

free里面的chunk是如何管理的?

也是使用链来管理的

从free空间里面找空闲的chunk(内存块),怎么找?

根据大小来找;比如现在我们需要一个4k大小的,就在free里面找一个4k的chunk,不行就找比4k大一点点的(比如:5k、8k、12k),然后找5k的,所以free里面是通过一种以free chunk的大小的链把一个一个的chunk挂在上面的

图解:

有三个链:2k、8k、16k,现在需要一个9k的,就在8k的链上找,找到一个12k的,可以,就用一下,用了9k还剩下3k,又挂到2k的链上。

游标(cursor)

一个SQL以及SQL对应的执行计划,叫做一个cursor,在library cache里面

父游标(parent cursor)

父游标说的是:SQL文本;同一个SQL可能对应多个执行计划(因为访问的用户不同,表的名字一样(都是t表),但是表的内容不一样;或者因为绑定参数的值的不同(同一个值,一个表里有1000万行,另外一个表里只有10行(这里表的名字相同)),执行计划也可能不同)

子游标(children cursor)

子游标就是:执行计划;子游标的个数不定,根据实际情况而定(比如10个、100个不确定)

version count(版本数量)

例如一个父游标有10个子游标,那么它的版本数量就是10

latch:锁(内存锁、闩锁),用来保护链的

图解:

现在有一个问题:oracle有好多上的server process,;假设server process1执行SQL1,server process2执行SQL2,然后server process1执行SQL1的时候要解析,在library cache里面没找到,SQL1就要发生硬解析;执行SQL2的时候,同样也如此,SQL2也需要硬解析;同时解析;

在解析的时候,就需要在free里面找一个free chunk,把它写进去;假设解析SQL1需要一个,9k的free chunk,解析SQL2,需要一个10k的free chunk,所以都需要在8k的链上找,这就有一个并发的问题:假设SQL1和SQL2找到相邻的两个free chunk;SQL1就要把它找到的free chunk2拿下来,把free chunk1指向free chunk3;SQL2把找到的free chunk3拿下来,然后把free chunk2指向free chunk4;这时候,free chunk2和free chunk3都没了,链就断了,所以对于这种情况链就需要并发保护,使用锁(latch)来进行保护;

latch(对于0号链申请的一个内存结构),用来保护0号链的,现在server process1读这个latch(里面有没有写相关信息),发现里面是空的,server process1就以S的方式写上,server process1以S的方式来访问0号链;

latch里面是空的,说明没有进程来对这个链进行保护修改;然后server process2也要来访问0号链,发现有一个进程在以S的方式访问,server process2想加一个X方式,但是server process1以S的方式持有着latch,server process2也想持有着latch,但是S和X不兼容,所以server process2就不能持有着latch,这时候server process2就发生一次latch misses(latch丢失);

假设server process1在cpu1上工作,server process2在cpu2上工作(有两个cpu),这时候,还有一个server process3在等着cpu空出来再进去,现在对于server process3来说两种选择:

1、server process2退出来(latch丢失),再进入cpu2,server process3工作一段时间以后退出来,server process2再进去,继续执行之前未执行完的操作,这个过程叫做:context switch(CS);

2、server process1持有latch的时间非常短,很短的时间内就执行完了,这时候,server process2不出来,它执行一个for循环,占用着cpu2,等server process1执行完S之后释放了latch就进去,这时候server process3就可以使用cpu1了;

再有假设,有四个cpu,server process2不出来,占用着cpu2,这时候server process3也持有着latch,server process2又再一次latch丢失了,然后server process4又持有着latch,server process2空转cpu,server process2又再一次latch丢失,server process2多次latch丢失以后,server process2就转为sleep状态,然后就退出cpu了,其他的server process就可以占用这个cpu了

因此,如果数据库出现严重的latch征用,就会表现出cpu很繁忙

sleep状态,说明出现了多次latch misses(latch丢失)

当server process1想访问0号链的时候,有两种访问方式:

1、S(共享锁)的方式(读链,在链上找大小)

2、X(排他锁)的方式(修改链,就是往链上挂东西和往链上摘东西)

S方式和X方式的关系

例如:1、SQL1:S 2、SQL1:S 3、SQL1:X

SQL2:S SQL2:X SQL2:S

1、SQL1和SQL2可以同时进行(S、S可以兼容)

2、SQL1和SQL2不能同时进行,要等SQL1找完了,SQL2再去修改(S、X不兼容)

3、SQL1和SQL2不能同时进行,要等SQL1修改完了,SQL2再去找(S、X不兼容)

latch的另外一种情况:

多个链用一个latch来保护,就很有可能出现latch丢失,所以我们可以通过调整参数来让多个链让多个latch来保护

latch的种类(绝大部分):

1、父latch:library cache latch

2、子latch:每一个链上latch(library cache latch里面一个一个的latch)

latch的工作方式:

1、sp1:S方式持有着latch

sp2:X方式,出现latch misses,空转着cpu,多次latch misses以后,变为sleep状态

2、sp1:S方式持有着latch 0

sp2:X方式,也想持有着latch 0,出现latch misses;但是sp2从latch 0上的链上能找到想要的东西,从latch 1上的链上也能找到想要的东西,一样;这时候,sp2就跑到latch 1去找东西了

但是绝大多数都是以第一种工作方式(willing to waiter)工作:愿意等,或者必须等的