说说自己对latch的一些理解,希望能和大家切磋交流。其实自己的这些个理解大部分来源于这些个书籍,列在下边:
1. Oracle Wait Interface: http://www.itpub.net/showthread.php?threadid=339860
感觉这本书在讲述具体的latch,比如说shared pool latch,library cache latch,cache buffers lru chain latch,hash latch这四个latch还是比较透彻的,但在总体上理解latch上似乎讲的不太好。不过下面的两本书,可以弥补这个遗憾,其实下面这两本书讲的东西基本上是一样的。
2.DSI405: http://www.itpub.net/showthread.php?threadid=527638
3.Steve Adams的Oracle8i Internal Services: http://www.eygle.com/archives/2005/...l_services.html
latch的东西简单说也挺容易理解的,就像OS中的读写冲突一样,会话SA在调整一个lru链表的时候,其它的会话就不能读取和调整这个链表了,latch所做的就是保护这一点。
latch是一种低级的串行化设备,它是为了保护SGA共享内存结构免受并发访问带来的潜在性破坏而引入的一种串性化手段,它只与SGA共享内存结构有关,与数据库对象无关。绝大多数latch是独占性访问,只有少数共享latch允许并发读。
latch分三种,父latch,子latch和独立latch。父latch和独立latch的分配是固化在oracle代码中的,是不可以调整的;子latch是在实例启动时根据参数动态分配的。父latch和子latch都是latch,本质上没有什么不同,都是可以被持有的,虽然说你除了library cache父latch之外很少能够看到父latch被持有,但本质上父latch和子latch没有任何的不同,把父latch理解为子latch的聚合信息的理解是错误的。
相关的视图:
v$session_wait中latch free等待事件的P1,P2,P3参数
P1:v$latch_parent.addr(请求和获取的是父latch和独立latch的情形下),v$latch_children.addr(请求和获取的是子latch的情形下),与v$latch.addr无关(那么这个参数的意义是什么呢?),x$bh.hladdr(请求和获取的是hash latch的情形下,保护buffer cache中这个block的hash latch的地址)
P2:V$latch.latch#,v$latchname.latch#
P3:已经sleep的次数
v$latch_parent:父latch和独立latch的信息;
v$latch_children:子latch的信息;
v$latch:三种latch的聚合信息。
V$latchholder:当前持有者,和V$session_wait是同一类视图
v$latch_misses
latch的请求和获取:
不再请求得到某个latch的唯一途径就是得到这个latch.有两种请求模式:no-wait和willing-to-wait。
no-wait的请求模式实际上很少用,主要用于下面两种情形:
1,请求的latch有多个侯选latch的情形下,它会使用hash算法确定它请求哪一个latch,然后以no-wait模式请求这个latch,如果失败了,它以no-wait模式请求下一个latch,直到获得一个latch或者所有的请求都失败,假如都失败的话,它将以willing-to-wait模式请求它最初请求的那个latch。
2。进程在持有某个latch的情形下,还会请求其他的latch,为了防止死锁的出现,orace规定,当以willing-to-wait模式请求latch时,如果它已经持有其它的latch的话,它必须按照一定的顺序去请求latch.每个latch都有一个level属性,当某个进程以willing-to-wait模式请求某个latch,且它已经持有其它latch时,它必须按照level由低到高的顺序去请求latch,也就是说它在请求某个latch的时候,它不能持有同级/更高级的latch.如果它持有同级/更高级的latch的时候,它首先会以no-wait模式去请求得到这个latch,如果失败的话,它只能放弃已经持有的高级latch,然后以willing-to-wait模式按照正确的顺序去请求这些个latch。
这种模式的请求统计记录在immediate_gets,immediate_misses两列中.
大多数情况下都是以willing-to-wait模式请求得到某个latch的。当所有的候选latch都请求失败或者根本就没有其它候选latch的情况下就是以willing-to-wait模式请求得到某个latch的。当它以willing-to-wait模式请求得到某个latch时,如果latch不是立即可用的,那么它也不会立即放弃CPU,而是不断的spin而后重试,spin的次数可以达到_spin_count,如果仍未得到latch,它就会让出cpu,sleep一段时间后被唤醒重新开始spin,直至得到这个latch.并且它每次sleep的时间是随着sleep的次数呈指数增长的,直至达到某个值后固定下来。这个最大值是_MAX_EXPONENTIAL_SLEEP(它没有持有任何latch的情形)或者_MAX_SLEEP_HOLDING_LATCH(它已经持有其它latch的情形)。当然为了防止它请求的latch的持有者死掉的情形,在它sleep四次之后在第五次sleep之前它会通知PMON检查该latch的持有进程是否还活着。
在它sleep前,它会更新v$session_wait,表明它正在等待latch free等待事件,在它被唤醒时它会更新v$session_wait,表明latch free等待事件结束,并且更新v$system_event,v$session_event中有关latch free的累计统计信息,需要注意的是v$system_event中的total_waits是叫醒一次就+1的,而v$latch中的sleeps是获取latch之后才一次性更新的。
这种模式下一些值的意义:
gets:逻辑请求的次数,请求一个latch直至得到这个latch,不管期间sleep了多少次,都算一个逻辑请求。
misses:spin(当然包括sleep过的)过的逻辑请求个数。
具体见如下伪代码:
[PHP]
if(获取了某个latch) then
gets:=gets+1;
if(spin过) then
if(期间持有其它latch) then
waits_holding_latch:=waits_holding_latch+1;
end if;
misses:=misses+1;
假定一共sleep了n次(n>=0)
sleeps:=sleeps+n;
if(n=0) then
spin_gets:=spin_gets+1;
elsif(n=1) then
sleep1:=sleep1+1;
elsif(n=2) then
sleep2:=sleep2+1;
依次类推下去
end if;
end if;
end if;
[/PHP]
关于一些个常见的latch:
1.shared pool latch
它是在共享池中分配和释放chunk时需要持有的latch,也就是说在硬分析时要互斥的持有这个latch.
2.library cache latch
它是在定位sql语句的分析书,执行计划时需要持有的latch,也就是说在软分析时要互斥的持有这个latch.
3.cache buffers lru chain latch
它是在buffer cache中分配block时需要持有的latch,也就是在每次非直接路径物理读前需要持有这个latch为它分配块。
4.hash latch
它是在定位data block在buffer cache中的buffer header时需要持有的latch,也就是说在每次逻辑读时需要持有的latch
实际上你可以发现在shared pool和buffer cache之间是存在着这样的一种相似性的,其实再往下走也是相似的:在shared pool中是要library cache lock/pin,而在buffer cache中是要buffer lock/pin,然后才能进行各自的工作的。对应的等待分别是library cache lock/pin 和buffer busy waits/write complete waits.
5.redo allocation latch
log buffer space被子分为片,每一个片就是一个os block,它的分配使用由这个latch保护
6.redo copy latch
在将PGA中的redo record拷贝到log buffer space时需要持有的latch
7.redo writing latch
这个latch保护的数据结构标识LGWR是否正在工作/LGWR是否已经被通知,以避免LGWR被不必要的通知写。
也不知从什么时候开始,有了一个很冒昧的想法,想针对一个简单的sql语句,比如说:update emp set salary=5000 where emp_no=5001 就它的硬分析/软分析,物理读/逻辑读,redo的生成,数据块的改变,LGWR,CKPT,DBWR,这个操作中会涉及到的oracle内部的一些个常见操作及期间latch的请求和释放写一些东西。可总感觉一些个东西闹清楚了,可总有一些个东西不是太清楚。不知哪位大侠可以开个头呀?!
举个例子吧!
说一下自己在看DSI405时对在buffer cache中改变块的一些个理解吧:
redo copy latch level#:4
redo allocation latch level#:5
buffer lock/pin(独占模式) -> 在PGA中建立改变向量,bundle成一个redo record -> 计算在log buffer中所需空间 -> 获取一个redo copy latch -> 获取一个redo allocation latch -> 在log buffer中分配空间 ->释放redo allocation latch -> 将redo record由PGA copy进log buffer ->在buffer cache中改变数据块,即应用改变向量(注意是先有redo,而后才改变块的) -> 在log buffer中标记redo entry为valid/invalid(即改变块成功与否) ->释放redo copy latch ->查看是否需要通知LGWR(比如说_log_io_size是否达到门限值,是否发现commit redo record等)
当然只是个人理解,欢迎讨论!
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10597822/viewspace-966387/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/10597822/viewspace-966387/