Latch等待应该说并不是一件坏事情。毕竟,设计Latch的目的就是用来让你等待的。Oracle使用Latch来保护SGA区中的关键数据结构不会在一个进程正在访问、修改时被另外一个进程访问,避免SGA区关键数据结构出现Corruption。暂时的waiting要比内存corruption更让人接受,不是么?不过,如果经常性的出现两个或多个进程等待同一个Latch,这就是一个问题了。因为,当Latch被释放(free)时,正在等待此Latch的多个进程将争抢Latch的所有权,而且只能有一个进程如愿获得Latch的所有权;而其他参与争抢的进程将消耗无效的CPU时间去spin、wait。随着参与争抢Latch的进程数量增加,将会造成严重的性能问题;而如果这个问题能够得到解决,这个性能问题会迅速的消失。一般来讲,共有三种不同的latch争用问题:1. 高CPU占用可能会触发latch争用问题。试想,如果一个已经获得latch所有权的进程不能迅速的获得CPU使用时间片,对这个latch的大量等待当然就不可避免了。为了避免由于CPU饥饿(CPU starvation)造成的latch争用问题,你应该保证你的系统不会持续较长时间的出现CPU占用率超过85%的压力高峰(当然,在某些系统中高CPU使用率是安全的)。很多系统问题(check for run-away process、paging)都会造成CPU的过度使用,所以说,在诊断一个Oracle性能问题的时候,你应该首先确保他确实是Oracle问题——而不是OS操作系统问题。2. Oracle预期latch被间断的、简短的占用。一些Latch争用性能问题的出现恰恰是因为一个Latch被超出预期的长时间占用。这种类型的问题通常是由于SGA区中的某个访问受latch保护的链表增长的太长(比如Shared Pool的碎片太多、buffer cache中的hash chains太长等等)。 这种类型的latch争用问题对_spin_count初始化参数的设置非常敏感。如果spin循环的时间恰恰短于这种类型的latch能够被获取的时间,这时尝试获取latch的进程就会停止spin,转入sleep状态;这种情况下,如果适当增加_spin_cout参数,使得spin循环的时间能够赶上占用Latch进程释放latch的时间,就可以避免进程sleep。当然,最好的调节方法是减少latch占用的时间,而不是增加latch spin的时间。3. Latch争用的性能问题也可能并不是由于Latch hold时间太长,而仅仅是因为获取Latch占用权的请求太过频繁了。最典型的一个例子是因为commit太过频繁而造成的’redo allocation’latch的争用。 这种情况下,最好的解决办法当然是避免太过频繁的latch request;但是很多情况下,最有效的解决方案也是最不可能的方案。通常,我们可以通过增加相应的child latch数量来缓解这个问题(比如 cache buffer lru latch),增加_spin_count对这种类型的性能问题没有帮助。如果我们不能降低latch request的频率(比如修改应用commit的频率),而且这个latch也不属于默认的long latch类别(默认好像只有两个latch是long latch: shared pool 、library cache);因为long latch默认支持latch posting特性,我们可以通过设置初始化参数_latch_wait_posting为2来强制对所有的latch类型都支持latch wait posting。 ——对于这一点,我心存疑虑,latch wait posting毫无疑问对某些latch会有负面影响,或者会过多的消耗资源;不然Oracle为什么只默认支持shared pool、libarary cache的wait posting呢;所以除非十分必要且经过测试,这种手段还是谨慎使用了。很显然的,要想恰当的解决latch争用造成的性能问题,首先我们得判断它是属于哪种类型的latch争用。以上3中类型中,CPU starvation应该是最容易判断的;其他两种类型的latch可以通过v$latch_misses加以区分。这个视图中包含了request或者hold每一个latch对应的Oracle Kernel位置。SQL> desc v$latch_misses Name Null? Type ----------------------------------------- -------- ---------------------------- PARENT_NAME VARCHAR2(50) WHERE VARCHAR2(64) NWFAIL_COUNT NUMBER
READ MORE