转载地址:http://www.itpub.net/thread-1803010-1-1.html
log buffer在Oracle的各个版本里一共发生过2次重大的改变:
1)多log buffer(redo strands)的出现(9I)
2)private redo和in memory undo的出现(10g)
你可能会补充说,还应该包括12c的多lgwr,是的,这也是一次革命性的改变,但是目前还没有对它有深刻的研究。我们暂时先把目光放回到11G之前。
ORACLE两次log buffer的重大改变,都跟redo allocation latch有着直接性的联系。本文以redo allocation latch切入点,描述log buffer的发展进化史。
由于题目写的比较大,不可能面面俱到,没有做太多细节性的描述。
redo allocation latch存在的问题
既然说是redo allocationlatch的问题,那么你可能会问,redo allocation latch出了什么问题,为什么要对它进行改进?
我来给大家一个简单的示例,一目了然的能知道一个小小的redo allocation latch存在什么严重的性能问题:
下面的代码里有一张wxh_tbd的表,表上无索引,我们更新了3条记录。下面的代码中,你只需要关注update的语句,其他的语句都是我采的快照,为了做分析用,你可以简单的把它忽略。
execute snap_latch.start_snap
execute snap_my_stats.start_snap
update wxh_tbd set object_name='t' where rownum 非常容易看到,仅仅是修改了3条记录,ORACLE就申请了三次的redo copy latch,redo allocation latch。产生了3个redo entries,也就是3个redorecord。
不难分析出每产生一个redo record,oracle就要申请一次redo copylatch+redo allocation latch。
那什么时候会产生一个redo record呢?它由什么组成的呢?
先回答第一个问题:每修改数据块一次!就产生一个redo record。
一般情况下,一个redo recored由一个undorecord(用来描述undo的修改)和一个redochange vector(用来描述数据块的修改)组成,如下:
REDO RECORD - Thread:1 RBA: 0x00036f.00000005.008c LEN: 0x00f8 VLD: 0x01
SCN: 0x0000.03ee485a SUBSCN: 1 03/13/2011 17:43:01
CHANGE #1 TYP:0 CLS:36 AFN:2 DBA:0x0080009a SCN:0x0000.03ee485a SEQ: 4 OP:5.1---------undo record
…
CHANGE #2 TYP:0 CLS: 1 AFN:11 DBA:0x02c0018a SCN:0x0000.03ee485a SEQ: 2OP:11.5--------redo change vector
…
上面的dump记录里,OP:5.1代表的是undo 块的修改,OP:11.5代表对数据块的修改。还有更多的OP代码,大家可以去参照了解下。
我们的实验里,修改了三次数据块,产生了三个redo record。如果object_name有索引的话,redo copy latch,redo allocation latch的数字至少是9.因为索引的每次update相当于是delete+insert,索引部分至少会增加6次redo copy latch,redoallocation latch的申请。
ORACLE里对于redo copy latch的数量一般是比较多的,依据你的CPU数来决定,缺省是CPU数的两倍(通过隐含参数_log_simultaneous_copies控制)。因此造成竞争的几率很低。
但是对于redo allocation latch来说,在多redostrands出现之前,就只有一把。在一个交易频繁的系统里,势必会造成对redo allocationlatch的竞争。
Redo allocation latch有什么用?
毋庸置疑,log buffer是个共享的地方,有很多会话需要在这个空间里为自己的日志分配空间,必须要机制去保证保证会话间彼此的日志不互相覆盖。
ORACLE里是通过redo allocation latch做到的这一点。
看上面的图,我们设定了log buffer 由9个logbuffer block组成,典型的,一般一个log buffer block跟磁盘的扇区大小匹配,512字节。SSD之类的固态盘很多已经不是这个扇区大小了。
这里面有2个指针需要特别指出来,一个是start of free space,一个是end of free space。这两个指针的移动靠redo allocation latch去保护。
我们可以举个例子来,这样更容易理解:
session 1,session 2,session 3同时想要在log buffer里分配空间,为了简化我们的场景,我们假设每个SESSION计划分配512字节的空间,也就是刚好是一个log buffer block块的大小。
redo allocation latch被session 1抢到,假如当前的startof free space的位置在块1,那么session 1持有redo allocation latch后,移动start of free space指针到2。然后释放latch。
由于session2,session 3没有抢到唯一的一把redoallocation latch,它不能去log buffer 里预留空间,只能等待latch释放。
session 1释放latch后,假如session 2获得了,它继续移动start of free space到3,然后释放latch。
通过上面的机制,保证了多个session并发往log buffer分配空间的时候,不会导致日志覆盖。
你可能会问:你怎么没有提到end offree space?
好,我们来说说这个end of freespace什么时候会移动。
假如session 2的记录是一个commit record,那么它会触发lgwr写,lgwr刷新完日志后(我们的例子中,会把1,2两个buffer刷到磁盘),移动end of free space到3。
这个时候end of freespace和start of free space在位置上是重合的
最后session3获得了redo allocation latch,移动startof free space到4.
经过前面的描述,相信你基本上明白了redo allocatoin latch为什么面临性能问题:争用严重,以及它存在的价值:保护空间分配。
/************这一块的内容大家了解下就可以,稍微的有点深入*****************************************************************/
在我们真正去看9I出现的redo strands之前,我们可以再看一个稍微深入的实验。这个实验里,仅仅跟我们第一次的实验,多了一个commit
execute snap_latch.start_snap
update wxh_tbd set object_name='t' where rownum |