`

Oracle Redo 并行机制

 
阅读更多

Redo log 是用于恢复和一个高级特性的重要数据,一个redo条目包含了相应操作导致的数据库变化的所有信息,所有redo条目最终都要被写入redo文件中去。Redo log buffer是为了避免Redo文件IO导致性能瓶颈而在sga中分配出的一块内存。一个redo条目首先在用户内存(PGA)中产生,然后由oracle服务进程拷贝到log buffer中,当满足一定条件时,再由LGWR进程写入redo文件。由于log buffer是一块“共享”内存,为了避免冲突,它是受到redo allocation latch保护的,每个服务进程需要先获取到该latch才能分配redo buffer。因此在高并发且数据修改频繁的oltp系统中,我们通常可以观察到redo allocation latch的等待。Redo写入redo buffer的整个过程如下:
 

    在PGA中生产Redo Enrey -> 服务进程获取Redo Copy latch(存在多个---CPU_COUNT*2) -> 服务进程获取redo allocation latch(仅1个) -> 分配log buffer -> 释放redo allocation latch -> 将Redo Entry写入Log Buffer -> 释放Redo Copy latch;

shared strand

    为了减少redo allocation latch等待,在oracle 9.2中,引入了log buffer的并行机制。其基本原理就是,将log buffer划分为多个小的buffer,这些小的buffer被成为strand(为了和之后出现的private strand区别,它们被称之为shared strand)。每一个strand受到一个单独redo allocation latch的保护。多个shared strand的出现,使原来序列化的redo buffer分配变成了并行的过程,从而减少了redo allocation latch等待。

    shared strand的初始数据量是由参数log_parallelism控制的;在10g中,该参数成为隐含参数,并新增参数_log_parallelism_max控制shared strand的最大数量;_log_parallelism_dynamic则控制是否允许shared strand数量在_log_parallelism和_log_parallelism_max之间动态变化。
 

SQL代码
  1. HELLODBA.COM>select  nam.ksppinm, val.KSPPSTVL, nam.ksppdesc   
  2.   2  from    sys.x$ksppi nam,   
  3.   3          sys.x$ksppsv val   
  4.   4  where nam.indx = val.indx   
  5.   5  --AND   nam.ksppinm LIKE '_%'   
  6.   6  AND   upper(nam.ksppinm) LIKE '%LOG_PARALLE%';   
  7.   
  8. KSPPINM                    KSPPSTVL   KSPPDESC   
  9. -------------------------- ---------- ------------------------------------------   
  10. _log_parallelism           1          Number of log buffer strands   
  11. _log_parallelism_max       2          Maximum number of log buffer strands   
  12. _log_parallelism_dynamic   TRUE       Enable dynamic strands   

    每一个shared strand的大小 = log_buffer/(shared strand数量)。strand信息可以由表x$kcrfstrand查到(包含shared strand和后面介绍的private strand,10g以后存在)。

SQL代码
  1. HELLODBA.COM>select indx,strand_size_kcrfa from x$kcrfstrand where last_buf_kcrfa != '00';   
  2.   
  3.       INDX STRAND_SIZE_KCRFA   
  4. ---------- -----------------   
  5.          0           3514368   
  6.          1           3514368   
  7.   
  8. HELLODBA.COM>show parameter log_buffer   
  9.   
  10. NAME                                 TYPE        VALUE   
  11. ------------------------------------ ----------- ------------------------------   
  12. log_buffer                           integer     7028736  

    关于shared strand的数量设置,16个cpu之内最大默认为2,当系统中存在redo allocation latch等待时,每增加16个cpu可以考虑增加1个strand,最大不应该超过8。并且_log_parallelism_max不允许大于cpu_count。

    注意:在11g中,参数_log_parallelism被取消,shared strand数量由_log_parallelism_max、_log_parallelism_dynamic和cpu_count控制。
 

Private strand

    为了进一步降低redo buffer冲突,在10g中引入了新的strand机制——Private strand。Private strand不是从log buffer中划分的,而是在shared pool中分配的一块内存空间。
 

SQL代码
  1. HELLODBA.COM>select * from V$sgastat where name like '%strand%';   
  2.   
  3. POOL         NAME                            BYTES   
  4. ------------ -------------------------- ----------   
  5. shared pool  private strands               2684928   
  6.   
  7. HELLODBA.COM>select indx,strand_size_kcrfa from x$kcrfstrand where last_buf_kcrfa = '00';   
  8.   
  9.       INDX STRAND_SIZE_KCRFA   
  10. ---------- -----------------   
  11.          2             66560   
  12.          3             66560   
  13.          4             66560   
  14.          5             66560   
  15.          6             66560   
  16.          7             66560   
  17.          8             66560   
  18. ...  

    Private strand的引入为Oracle的Redo/Undo机制带来很大的变化。每一个Private strand受到一个单独的redo allocation latch保护,每个Private strand作为“私有的”strand只会服务于一个活动事务。获取到了Private strand的用户事务不是在PGA中而是在Private strand生成Redo,当flush private strand或者commit时,Private strand被批量写入log文件中。如果新事务申请不到Private strand的redo allocation latch,则会继续遵循旧的redo buffer机制,申请写入shared strand中。事务是否使用Private strand,可以由x$ktcxb的字段ktcxbflg的新增的第13位鉴定:
 

SQL代码
  1. HELLODBA.COM>select decode(bitand(ktcxbflg, 4096),0,1,0) used_private_strand, count(*)   
  2.   2    from x$ktcxb   
  3.   3   where bitand(ksspaflg, 1) != 0   
  4.   4     and bitand(ktcxbflg, 2) != 0   
  5.   5   group by bitand(ktcxbflg, 4096);   
  6.   
  7. USED_PRIVATE_STRAND   COUNT(*)   
  8. ------------------- ----------   
  9.                   1         10   
  10.                   0          1  

    对于使用Private strand的事务,无需先申请Redo Copy Latch,也无需申请Shared Strand的redo allocation latch,而是flush或commit是批量写入磁盘,因此减少了Redo Copy Latch和redo allocation latch申请/释放次数、也减少了这些latch的等待,从而降低了CPU的负荷。过程如下:
 

    事务开始 -> 申请Private strand的redo allocation latch (申请失败则申请Shared Strand的redo allocation latch) -> 在Private strand中生产Redo Enrey -> Flush/Commit -> 申请Redo Copy Latch -> 服务进程将Redo Entry批量写入Log File -> 释放Redo Copy Latch -> 释放Private strand的redo allocation latch
 

    注意:对于未能获取到Private strand的redo allocation latch的事务,在事务结束前,即使已经有其它事务释放了Private strand,也不会再申请Private strand了。
 

    每个Private strand的大小为65K(64位系统中为129K)。10g中,shared pool中的Private strands的大小就是活跃会话数乘以65K,而11g中,在shared pool中需要为每个Private strand额外分配4k的管理空间,即:数量*69k。
 

SQL代码
  1. --10g:   
  2. SQL> select * from V$sgastat where name like '%strand%';   
  3.   
  4. POOL         NAME                            BYTES   
  5. ------------ -------------------------- ----------   
  6. shared pool  private strands               1198080   
  7.   
  8. HELLODBA.COM>select trunc(value * KSPPSTVL / 100) * 65 * 1024   
  9.   2    from (select value from v$parameter where name = 'transactions') a,   
  10.   3         (select val.KSPPSTVL   
  11.   4            from sys.x$ksppi nam, sys.x$ksppsv val   
  12.   5           where nam.indx = val.indx   
  13.   6             AND nam.ksppinm = '_log_private_parallelism_mul') b;   
  14.   
  15. TRUNC(VALUE*KSPPSTVL/100)*65*1024   
  16. -------------------------------------   
  17.                               1198080   
  18.   
  19. --11g:   
  20. HELLODBA.COM>select * from V$sgastat where name like '%strand%';   
  21.   
  22. POOL         NAME                            BYTES   
  23. ------------ -------------------------- ----------   
  24. shared pool  private strands                706560   
  25.   
  26. HELLODBA.COM>select trunc(value * KSPPSTVL / 100) * (65 + 4) * 1024   
  27.   2    from (select value from v$parameter where name = 'transactions') a,   
  28.   3         (select val.KSPPSTVL   
  29.   4            from sys.x$ksppi nam, sys.x$ksppsv val   
  30.   5           where nam.indx = val.indx   
  31.   6             AND nam.ksppinm = '_log_private_parallelism_mul') b;   
  32.   
  33. TRUNC(VALUE*KSPPSTVL/100)*(65+4)*1024   
  34. -------------------------------------   
  35.                                706560   

    Private strand的数量受到2个方面的影响:logfile的大小和活跃事务数量。
 

    参数_log_private_mul指定了使用多少logfile空间预分配给Private strand,默认为5。我们可以根据当前logfile的大小(要除去预分配给log buffer的空间)计算出这一约束条件下能够预分配多少个Private strand:
 

SQL代码
  1. HELLODBA.COM>select bytes from v$log where status = 'CURRENT';   
  2.   
  3.      BYTES   
  4. ----------   
  5.   52428800   
  6.   
  7. HELLODBA.COM>select trunc(((select bytes from v$log where status = 'CURRENT') - (select to_number(value) from v$parameter where name = 'log_buffer'))*   
  8.   2         (select to_number(val.KSPPSTVL)   
  9.   3            from sys.x$ksppi nam, sys.x$ksppsv val   
  10.   4           where nam.indx = val.indx   
  11.   5             AND nam.ksppinm = '_log_private_mul') / 100 / 66560)   
  12.   6         as "calculated private strands"  
  13.   7    from dual;   
  14.   
  15. calculated private strands   
  16. --------------------------   
  17.                          5   
  18.   
  19. HELLODBA.COM>select count(1) "actual private strands" from x$kcrfstrand where last_buf_kcrfa = '00';   
  20.   
  21. actual private strands   
  22. ----------------------   
  23.                      5   

    当logfile切换后(和checkpoint一样,切换之前必须要将所有Private strand的内容flush到logfile中,因此我们在alert log中可能会发现日志切换信息之前会有这样的信息:"Private strand flush not complete",这是可以被忽略的),会重新根据切换后的logfile的大小计算对Private strand的限制:
 

SQL代码
  1. HELLODBA.COM>alter system switch logfile;   
  2.   
  3. System altered.   
  4.   
  5. HELLODBA.COM>select bytes from v$log where status = 'CURRENT';   
  6.   
  7.      BYTES   
  8. ----------   
  9.  104857600   
  10.   
  11. HELLODBA.COM>select trunc(((select bytes from v$log where status = 'CURRENT') - (select to_number(value) from v$parameter where name = 'log_buffer'))*   
  12.   2         (select to_number(val.KSPPSTVL)   
  13.   3            from sys.x$ksppi nam, sys.x$ksppsv val   
  14.   4           where nam.indx = val.indx   
  15.   5             AND nam.ksppinm = '_log_private_mul') / 100 / 66560)   
  16.   6         as "calculated private strands"  
  17.   7    from dual;   
  18.   
  19. calculated private strands   
  20. --------------------------   
  21.                         13   
  22.   
  23. HELLODBA.COM>select count(1) "actual private strands" from x$kcrfstrand where last_buf_kcrfa = '00';   
  24.   
  25. actual private strands   
  26. ----------------------   
  27.                     13  

    参数_log_private_parallelism_mul用于推算活跃事务数量在最大事务数量中的百分比,默认为10。Private strand的数量不能大于活跃事务的数量。
 

SQL代码
  1. HELLODBA.COM>show parameter transactions   
  2.   
  3. NAME                                 TYPE        VALUE   
  4. ------------------------------------ ----------- ------------------------------   
  5. transactions                         integer     222   
  6. transactions_per_rollback_segment    integer     5   
  7. HELLODBA.COM>select trunc((select to_number(value) from v$parameter where name = 'transactions') *   
  8.   2         (select to_number(val.KSPPSTVL)   
  9.   3            from sys.x$ksppi nam, sys.x$ksppsv val   
  10.   4           where nam.indx = val.indx   
  11.   5             AND nam.ksppinm = '_log_private_parallelism_mul') / 100 )   
  12.   6         as "calculated private strands"  
  13.   7    from dual;   
  14.   
  15. calculated private strands   
  16. --------------------------   
  17.                         22   
  18.   
  19. HELLODBA.COM>select count(1) "actual private strands" from x$kcrfstrand where last_buf_kcrfa = '00';   
  20.   
  21. actual private strands   
  22. ----------------------   
  23.                     22  

    注:在预分配Private strand时,会选择上述2个条件限制下最小一个数量。但相应的shared pool的内存分配和redo allocation latch的数量是按照活跃事务数预分配的。
 

    因此,如果logfile足够大,_log_private_parallelism_mul与实际活跃进程百分比基本相符的话,Private strand的引入基本可以消除redo allocation latch的争用问题。
 

参考至:http://www.hellodba.com/reader.php?ID=28&lang=CN

如有错误,欢迎指正

邮箱:czmcj@163.com

分享到:
评论

相关推荐

    Oracle Redo并行机制

    Redo log 是用于恢复和一个高级特性的重要数据,一个redo条目包含了相应操作导致的数据库变化的所有信息,所有redo条目最终都要被写入redo文件中去。Redo log buffer是为了避免Redo文件IO导致性能瓶颈而在sga中分配...

    ORACLE9i_优化设计与系统调整

    §9.9.3 Oracle并行服务器 110 §9.10 Oracle数据库增长的规划 111 §9.10.1 不同增长表的配置 111 §9.10.2 对增长表进行规划和分析 112 第10章 数据库结构设计要点 113 §10.1 分析阶段的对表的理解 113 §10.2 ...

    让Oracle跑得更快 Oracle 10g性能分析与优化思路.part2.rar

    8.2 并行处理的机制 189 8.3 读懂一个并行处理的执行计划 191 8.4 一个很常见的并行执行等待事件 192 8.5 并行执行的适用范围 194 8.5.1 并行查询 194 8.5.2 并行ddl操作 195 8.5.3 并行dml操作 203 8.6 并行执行的...

    深入解析Oracle.DBA入门进阶与诊断案例

    9.5.7 Oracle 10g/11g Latch机制的变化 467 第10章 性能诊断与SQL优化 471 10.1 使用AUTOTRACE功能辅助SQL优化 471 10.1.1 AUTOTRACE功能的启用 471 10.1.2 Oracle 10g AUTOTRACE功能的增强 473 10.1.3 ...

    构建最高可用Oracle数据库系统 Oracle 11gR2 RAC管理、维护与性能优化

    1.3.1双机并行 1.3.2高可用性 1.3.3易伸缩性 1.3.4低成本 1.3.5高吞吐量 1.4 RAC存在的问题 1.4.1稳定性 1.4.2高性能 1.5 RAC软件 1.5.1存储管理软件 1.5.2集群管理软件 1.5.3数据库管理软件 1.6本章小...

    Oracle 9i&10g编程艺术:深入数据库体系结构(全本)含脚本

    目录回到顶部↑第1章 开发成功的Oracle应用 1 1.1 我的方法 2 1.2 黑盒方法 4 1.3 开发数据库应用的正确(和不正确)方法 8 1.3.1 了解Oracle体系结构 8 1.3.2 理解并发控制 14 1.3.3 多版本 19 1.3.4 数据库...

    让Oracle跑得更快 Oracle 10g性能分析与优化思路.part1.rar

    8.2 并行处理的机制 189 8.3 读懂一个并行处理的执行计划 191 8.4 一个很常见的并行执行等待事件 192 8.5 并行执行的适用范围 194 8.5.1 并行查询 194 8.5.2 并行ddl操作 195 8.5.3 并行dml操作 203 8.6 并行执行的...

    oracle动态性能表

    32 代表并行活动 64 代表表访问 128 代表调试信息 注意:Statistic#的值在不同版本中各不相同,使用时要用Name做为查询条件而不要以statistic#的值做为条件。 使用v$sysstat中的数据  该视图中数据常被用于监控...

    学习ORACLE动态性能表.doc

    按照OracleDocument中的描述,v$sysstat存储自数据库实例运行那刻起就开始累计全实例(instance-wide)的资源使用情况。 类似于v$sesstat,该视图存储下列的统计信息: 1>.事件发生次数的统计(如:user commits) 2>....

    Oracle编程艺术

    3.4.1 简要回顾文件系统机制..........................................................180 3.4.2 Oracle数据库中的存储层次体系..............................................181 3.4.3 字典管理和本地管理的表...

    Oracle 9i&10g编程艺术:深入数据库体系结构

    第1章 开发成功的Oracle应用程序 第2章体系结构概述 第3章 文件 第4章 内存结构 ...第9章 redo与undo 第10章 数据库表 第11章 索引 第12章 数据类型 第13章 分区 第14章 并行执行 第15章 数据加载和卸载

    收获不知Oracle

    2.3.2.7 并行设置,飞船速度 79 2.3.3 精彩的总结与课程展望 80 2.3.3.1 最大的收获应该是思想80 2.3.3.2 老师的课程展望与规划81 第3章神奇,走进逻辑体系世界 84 3.1 长幼有序的逻辑体系 84 3.2 逻辑体系从老余...

    ORACLE DBA 手册

    避免动态空间管理Oracle数据库增长空间是就以区的单位扩展的,区由块组成,区的增长方式有两种,一种是allocation_type是UNIFORM,每次分配区的大小是一致的,另一种Allocation_type是SYSTEM自动分配。区的大是...

    ORACLE必学

    初学必备Parallel 用来指定为加速该表的全表扫描可以使用的并行查询进程个数. Cache 用来指定该表为最应该缓存在SGA数据库缓冲池中的候选项. Cluster 用来指定该表所存储的 cluster. Tablespace 用来指定用数据库的...

    mysql数据库my.cnf配置文件

    # MySQL的最大连接数,如果服务器的并发连接请求量比较大,建议调高此值,以增加并行连接数量,当然这建立在机器能支撑的情况下,因为如果连接数越多,介于MySQL会为每个连接提供连接缓冲区,就会开销越多的内存,...

Global site tag (gtag.js) - Google Analytics