先来看下Latch和Lock的区别
1. Latch是对内存数据结构提供互斥访问的一种机制,而Lock是以不同的模式来套取共享资源对象,各个模式间存在着兼容或排斥,从这点看出,Latch的访问,包括查询也是互斥的,任何时候,只能有一个进程能pin住内存的某一块,幸好这个过程是相当的短暂,否则系统性能将没的保障,现在从9I开始,允许多个进程同时查询相同的内存块,但性能并没有想象中的好。
2. Latch只作用于内存中,他只能被当前实例访问,而L ock作用于数据库对象,在RAC体系中实例间允许Lock检测与访问
3. Latch是瞬间的占用,释放,Lock的释放需要等到事务正确的结束,他占用的时间长短由事务大小决定
4. Latch是非入队的,而Lock是入队的
5. Latch不存在死锁,而Lock中存在(死锁在Oracle中是非常少见的)
看看下面这个例子,你会感觉到Latch的存在
SQL> CREATE TABLE MYTEST AS SELECT OBJECT_NAME FROM USER_OBJECTS WHERE ROWNUM <= 4;
Table created
SQL > SET TIMING ON
SQL >
DECLARE lv_name VARCHAR2(25) := '';
BEGIN
FOR i IN 1..100000 LOOP
SELECT OBJECT_NAME INTO lv_name FROM MYTEST WHERE ROWNUM = 1;
END LOOP;
END;
/
PL/SQL procedure successfully completed
Executed in 3.359 seconds
这个进程不断的访问表上的同一个数据块,他先会物理读取数据块到数据缓冲区,然后在内存中不断的获取这个块的latch,现在只有单个进程,运行的还好,10万次用了3秒多,但当我拉出4个窗口同时并发的运行这个语句时,问题就出现了,多个进程PIN同一个数据块,每个大概花了15秒,并且看到他们一个一个的结束,到最后只剩一个时一闪就过去了,因为没人和他抢了,这个实验展现了Latch竞争的现象,对于9I提出的查询可以共享Latch在此我表示了质疑。
现在来看看进程获取Latch的详细过程,任何时候,只有一个进程可以访问内存中的某一个块(9I提出的Latch共享我不想考虑),如果进程因为别的进程正占用块而无法获得Latch时,他会对CPU进行一次spin(旋转),时间非常的短暂,spin过后继续获取,不成功仍然spin,直到spin次数到达阀值限制(这个由隐含参数_spin_count指定),此时进程会停止spin,进行短期的休眠,休眠过后会继续刚才的动作,直到获取块上的Latch为止。进程休眠的时间也是存在算法的,他会随着spin次数而递增,以厘秒为单位,如1,1,2,2,4,4,8,8,。。。休眠的阀值限制由隐含参数_max_exponential_sleep控制,默认是2秒,如果当前进程已经占用了别的Latch,则他的休眠时间不会太长(过长会引起别的进程的Latch等待),此时的休眠最大时间有隐含参数_max_sleep_holding_latch决定,默认是4厘秒。这种时间限制的休眠又称为短期等待,另外一种情况是长期等待锁存器(Latch Wait Posting),此时等待进程请求Latch不成功,进入休眠,他会向锁存器等待链表(Latch Wait List)压入一条信号,表示获取Latch的请求,当占用进程释放Latch时会检查Latch Wait List,向请求的进程传递一个信号,激活休眠的进程。Latch Wait List是在SGA区维护的一个进程列表,他也需要Latch来保证其正常运行,默认情况下share pool latch和library cache latch是采用这个机制,如果将隐含参数_latch_wait_posting设置为2,则所有Latch都采用这种等待方式,使用这种方式能够比较精确的唤醒某个等待的进程,但维护Latch Wait List需要系统资源,并且对Latch Wait List上Latch的竞争也可能出现瓶颈。
如果一个进程请求,旋转,休眠Latch用了很长时间,他会通知PMON进程,查看Latch的占用进程是否已经意外终止或死亡,如果是则PMON会清除释放占用的Latch资源。
现在大家可以明白,对Latch获取的流程了,请求-SPIN-休眠-请求-SPIN-休眠。。。占用,这里有人会问为什么要SPIN,为什么不直接休眠等待?这里要明白休眠意味着什么,他意味着暂时的放弃CPU,进行上下文切换(context switch),这样CPU要保存当前进程运行时的一些状态信息,比如堆栈,信号量等数据结构,然后引入后续进程的状态信息,处理完后再切换回原来的进程状态,这个过程如果频繁的发生在一个高事务,高并发进程的处理系统里面,将是个很昂贵的资源消耗,所以他选择了spin,让进程继续占有CPU,运行一些空指令,之后继续请求,继续spin,直到达到_spin_count值,这时会放弃CPU,进行短暂的休眠,再继续刚才的动作,Oracle软件就是这么设计的,世界大师们的杰作,自然有他的道理,我就不在这上面再费文字了。
系统发生关于Latch的等待是没发避免的,因为这是Oracle的运作机制,当你看到很高的Latch get时并不意味着你的系统需要调整,有时候很高的get值背后只有很短的等待时间,我们调整的对象应该以消耗的时间来圈定,而不是看到一个很高的获取次数值,当然,获取值异常的高出别的等待时间几十万倍时我们还是要关心的,Oracle关于Latch的等待非常繁多,主要的包括share pool,library cache,cache buffer chains,buffer busy wait,每一个的调整几乎都可以写几页纸,以后慢慢完成吧。
get表示请求对象、获得对象句柄;
pin根据句柄找到实际对象并执行,但对象内容可能因为老化而pin不到所以出现reload;
一个session需要使用一个object时,如果是初次使用,则必然是先get然后pin并维护这个object的句柄。下次再使用这个object时,因为已经维护该句柄,所以直接pin而没有了get过程。如果对象老化则移除共享池,再次请求则会出现reload
联系客服