IMU&PRVS(译)

      private strand 是在Shared pool中的,,在会话请求修改时,,会同步的分配log buffer中的空间给它,但是变更是独立的在shared pool中处理,目的是提高log buffer的处理并发度,从而提高效率,,private strand一般配合IMU一起使用
         实际上,不管你是用IMU+PRVS或者传统的写REDO方式,这两种方式产生的UNDO块的内容都是一样的,REDO LOG FILE的内容也是一样的。主要的区别在于时间和顺序;在使用IMU时,同样也有重做记录数目的减少,但是REDO CHANGE VECTOR是一样多的。
——–传统小事务写过程:
        修改表或索引块–这个要求你生成REDO CHANGE VECTOR
        同时,你必须记录足够的信息来回滚这次改动–这是UNDO RECORD
        UNDO RECORD是存储在UNDO BLOCK中的,所以你生成的一个改动向量来描述你对UNDO BLOCK的改动
        ORACLE集成这两个改动向量为一个REDO RECORD–在会话统计信息中增加到REDO ENTRIES里
        ORACLE使用REDO ALLOCATION和REDO COPY LATCHES来请求空间和复制这个记录到REDO LOG BUFFER中
        假如说,你插入10条记录,每次插入一条,这个表有4个索引,那么将会生成50个REDO RECORDS和50个UNDO RECORDS,而且还要获取REDO LATCH 50次(每行数据生成5个REDO RECORDS,1个行数据的,4个索引的REDO RECORD)

——–在IMU启用的情况下
        当你第一次修改表记录时,ORACLE从SHARED POOL中分配一个PRIVATE REDO BUFFER(后面简称PRVS)和一个私有的UNDO BUFFER
        IN MEMORY UNDO(后面简称IMU) BUFFER实际上是为REDO服务的BUFFER,它描述的是UNDO的改动
        当你修改表和索引时,每一个改动向量都被写到PRVS中
        与此同时,每一个UNDO的改动向量都记录到IMU BUFFER中
        改动向量的总数,还有这些改动向量的内容都和传统的改动向量相同的
        当你COMMIT的时候,ORACLE将两个BUFFER合并成一个大的REDO RECORD并将它写入到REDO BUFFER中
        同时所有的这100个改动向量都被应用到表、索引和UNDO块中,当然COMMIT时,还有其他的一些关联动作也将发生,比如说:释放锁、为事务生成SCN、块清理等
        最重要的不同就是REDO的量,传统的REDO量有50个REDO RECORD HEADER(600 BYTES),而IMU中只有一个REDO RECORD HEADER(12 BYTES)

         当然,对于这种结构,有一非常重要的特征。她适用于小的事务–PRVS受限于64KB或者128KB(取决于CPU的BIT-COUNT),所以当一个事务非常大的时候,它就体现不出优势来了,ORACLE将最开始的那一部分使用IMU+PRVS的方式刷到REDO BUFFER里去,然后继续使用传统的方式生成REDO。

         从x$kcrfstrand中可以看到一些关于PUBLIC和PRIVATE REDO BUFFER的线程信息,从下面例子可以看到:有2个PUBLIC THREADS和9个PRIVATE THREADS,但是有4个PRIVATE THREADS被动态禁止了。

SQL> SELECT INDX,PTR_KCRF_PVT_STRAND,STRAND_SIZE_KCRFA FROM X$KCRFSTRAND;

      INDX PTR_KCRF STRAND_SIZE_KCRFA
---------- -------- -----------------
         0 00                 3494400        public
         1 00                 3494400
         2 20F27C80             66560        private
         3 20F38080             66560
         4 20F48480             66560
         5 20F58880             66560
         6 20F68C80             66560
         7 20F79080             66560
         8 00                   66560        dynamically disabled
         9 00                   66560
        10 00                   66560
        11 00                   66560

如果你查看X$KTIFP,能看到与UNDO BUFFER相关的信息,包含了UNDO内存地址和与PRVS相关联的内存地址。在这个例中,我获得一个插入三行数据的活动事务,每次插入一条。这个查询显示了开始、当前的高水位和10个IMU BUFFER的使用情况,其中一个BUFFER显示了与REDO BUFFER关联的信息。注意,当UNDO BUFFER使用1K左右时,REDO BUFFER使用大约8K:

select ktifpno,ktifpxcb tx_addr, 
 ktifpupb undo_start,
 ktifpupc undo_cur, 
 to_number(ktifpupc,'XXXXXXXX') -  to_number(ktifpupb,'XXXXXXXX')  undo_usage, 
 ktifprpb  redo_start, 
 ktifprpc  redo_cur, 
 to_number(ktifprpc,'XXXXXXXX') -  to_number(ktifprpb,'XXXXXXXX')  redo_usage 
from   x$ktifp  order by    ktifpno ;

   KTIFPNO TX_ADDR  UNDO_STA UNDO_CUR UNDO_USAGE REDO_STA REDO_CUR REDO_USAGE
---------- -------- -------- -------- ---------- -------- -------- ----------
         0 00       20FCB800 20FCB800          0 00       00                0
         1 20EFB500 20FDC400 20FDC7E8       1000 20F38080 20F3A21C       8604
         2 00       20FED000 20FED000          0 00       00                0
         3 00       20435000 20435000          0 00       00                0
         4 00       20445C00 20445C00          0 00       00                0
         5 00       20456800 20456800          0 00       00                0
         6 00       20467400 20467400          0 00       00                0
         7 00       20478000 20478000          0 00       00                0
         8 00       20488C00 20488C00          0 00       00                0
         9 00       20499800 20499800          0 00       00                0

证明了,UNDO和REDO BUFFER实际上是分开的,并且“UNDO的REDO”不存放在REDO BUFFER中。下一个例子是在COMMIT之后,启动了一新的事务来删除这三行数据:

   KTIFPNO TX_ADDR  UNDO_STA UNDO_CUR UNDO_USAGE REDO_STA REDO_CUR REDO_USAGE
---------- -------- -------- -------- ---------- -------- -------- ----------
         0 00       20FCB800 20FCB800          0 00       00                0
         1 20EFB500 20FDC400 20FDF218      11800 20F38080 20F38428        936
         2 00       20FED000 20FED000          0 00       00                0
         3 00       20435000 20435000          0 00       00                0
         4 00       20445C00 20445C00          0 00       00                0
         5 00       20456800 20456800          0 00       00                0
         6 00       20467400 20467400          0 00       00                0
         7 00       20478000 20478000          0 00       00                0
         8 00       20488C00 20488C00          0 00       00                0
         9 00       20499800 20499800          0 00       00                0

注意:UNDO BUFFER现在已经使用了11KB,但REDO BUFFER只使用了1KB不到
        顺便,你可能会想到可能在这种内存结构中产生的记录量会比较大些。你应该是对的:这里有些BUFFER的开销,他们有些不被复帛到REDO LOG或者UNDO BLOCK中。举个例子,在我提交事务之后,我INSERT的那个SESSION显示了以下信息:

Name                                                 Value
----                                                 -----
redo entries                                             1
redo size                                            6,944      -- not 8,604
undo change vector size                                256    -- not 1,000
IMU commits                                              1
IMU undo allocation size                             1,000

出处:http://jonathanlewis.wordpress.com/2010/12/23/private-redo/
     隐含参数_in_memory_undo用于控制IMU特性的开关,可以在会话/系统级立即生效,默认为true。另外一个隐含参数_IMU_pools则控制IMU pool的数量,默认为3。

    未完待续……

About 数据块

非著名DBA,梦想是成为ORACLE骨灰级玩家!
This entry was posted in REDO&UNDO. Bookmark the permalink.

发表评论