Chinaunix首页 | 论坛 | 博客
  • 博客访问: 401922
  • 博文数量: 127
  • 博客积分: 4025
  • 博客等级: 上校
  • 技术积分: 1980
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-18 18:09
文章分类

全部博文(127)

文章存档

2009年(127)

我的朋友

分类: Oracle

2009-09-06 21:11:56

如果是redo copy的丢失率很严重,则可以考虑增加隐藏参数:_log_simultaneous_copies的值。该参数定义了redo copy latch的数量,该参数缺省为CPU数量的两倍。从8i起,该参数成为隐藏参数,因为不适合为系统增加过多的redo copy latch,特别是在OLTP环境中。增加该参数可以减少前台对redo copy latch的等待,但是要注意,过多的redo copy latch可能会使得LGWR等待更长的时间。因为前面我们已经知道,LGWR在确定了要写哪些日志块以后,会等待前台进程完成对这些日志块的操作以后, 才开始正式写入。所以,如果很多的前台进程都可以获得redo copy latch以后,就可能引起LGWR要等很长时间才能开始正式写入。

如果是redo allocation的丢失率很严重,需要考虑是否有可能减少重做记录的生成。具体可以看下面有关如何减少重做记录的部分。8i以前,存在一个参数: log_small_entry_max_size,该参数说明了当重做记录的尺寸小于该参数指定值时,使用redo allocation latch来保护重做记录拷贝到日志缓冲区的过程,否则,如果重做记录大于该参数值时,使用redo copy latch来保护这个过程。但是从8i以后,取消了该参数,只要拷贝重做记录到日志缓冲区,就获得redo copy latch。

如果是redo writing的丢失率很严重,则说明LGWR写的时间过长,导致其他进程无法获得该latch。这时可以通过减小_log_io_size来增加LGWR写的频率。具体_log_io_size的用法可以参考下面log buffer的设置部分。
3.3 log buffer的设置
对于日志缓冲区来说,设置过小,容易引起log buffer space等待事件。但也不是说设置的越大就越好的,设置过大,由于LGWR进程会不断启动刷新日志缓冲区从而释放内存,所以可能会根本用不上多余的内存,从而浪费内存。

设置合适的日志缓冲区大小,目的是为了能够让LGWR进程合理的触发。理想情况下是,一方面,在LGWR进程向联机日志文件中写重做记录时,日志缓冲区中 还是有剩余的可用空间以供其他进程所使用;另一方面,当LGWR进程完成时,日志缓冲区中的剩余可用空间不要很多,因为这时LGWR所写入日志文件的日志 块就可以释放出来了,成为新的剩余可用空间。然后,LGWR可以再次启动刷新脏的日志块。如此良性循环,就能在满足性能的前提下,充分利用日志缓冲区。没 必要盲目的把日志缓冲区设置的很大,完全可以把节省下来的内存交给比如数据块缓冲区(buffer cache)等这样更需要内存的组件。

我们已经知道,当重做记录达到日志缓冲区的1/3或1M时,就会触发LGWR进程。也就是说,oracle缺省认为LGWR进程在写日志缓冲区大小的 1/3或1M的重做记录的过程中,剩下的日志缓冲区可以供新的重做记录的需要。当LGWR写完以后,那么这1/3或1M的日志缓冲区就又可以成为可用的日 志块以容纳新的重做记录了。由此,我们可以很容易推导出,当我们设置日志缓冲区达到3M(3×1M)以上时,这时多余出来的日志缓冲区实际上并不能用得 上,换句话说,多余出来的内存就被我们浪费了。

不过,本质上,这个启动LGWR的限度值是由一个隐藏参数:_log_io_size决定的,如下所示。该参数表示日志缓冲区中存在多少个脏日志块时触发 LGWR进程写脏日志块。缺省情况下,该参数为0,表示当脏日志块占日志缓冲区的1/3时触发LGWR进程。如果设置了该参数为一个非0值,则如果该参数 值不大于日志缓冲区大小的1/2时,该参数值作为启动LGWR的限度值。否则,如果该参数值大于日志缓冲区的1/2时,忽略该参数值,以日志缓冲区大小的 1/2为启动LGWR的限度值。不管怎么样,脏日志块的容量只要超过1M,就必然触发LGWR进程。
SQL> select x.ksppinm, y.ksppstvl, x.ksppdesc from x$ksppi x , x$ksppcv y
2 where x.indx = y.indx and ksppinm like '%_log_io_size%';
KSPPINM KSPPSTVL KSPPDESC
------------- ---------- -------------------------------------------------------
_log_io_size 0 automatically initiate log write if this many redo blocks in buffer
在设置日志缓冲区时,可以参考下面这个建议的公式来计算:1.5×(平均每个事务所产生的重做记录大小×每秒提交的事务数量)。
首先先找到总事务量是多少:
select a.value as trancount from v$sysstat a,v$statname b
where a.statistic# = b.statistic# and b.name = 'user commits';
然后,找到系统总共的运行时间:
select trunc(sysdate - startup_time)*24*60*60 as seconds from v$instance;

第三,找到所产生的所有重做记录大小:
select value as redoblocks from v$sysstat
where
name = 'redo blocks written';
最后,我们可以分别计算公式中的值:平均每个事务所产生的重做记录大小= redoblocks/trancount;每秒提交的事务数量=trancount/seconds。 这样,最后所建议的日志缓冲区的大小可以写为:
1.5* (redoblocks/trancount)* (trancount/seconds)
3.4 减少生成的重做记录的方法
   要优化日志缓冲区的使用,最直接、最容易看到效果的方法当然就是阻止重做记录的产生了。也就是说对DML语句不记录数据块的改变过程,从而减少对日志缓 冲区的使用。但是,毫无疑问,这完全违背了oracle设立日志缓冲区以及联机日志文件的目的。由于没有产生对数据块变化的记录,那么如果数据库发生崩 溃,将导致无法恢复到数据库崩溃前一秒的状态,也就必然发生数据丢失。

    通过使用NOLOGGING短语或者append提示来阻止重做记录的产生。该短语可以用在表空间上,表示该表空间里的对象缺省都不产生日志。也可以将表 或者索引定义为NOLOGGING,这样该表上的DML操作都不生成重做记录,而对索引的重建也不生成重做记录。还可以直接用在以下的SQL语句中:
1) 直接路径装载(Direct Loader)以及直接路径插入(对insert使用append提示:insert /*+ append*/)。
2) create table table-name NOLOGGING as select …(CTAS)
3) alter table table-name NOLOGGING move tablespace tablespace-name
4) create index index-name NOLOGGING …
5) alter index index-name NOLOGGING rebuild…
6) 分区操作中,可以添加NOLOGGING短语。
7) truncate命令总是以NOLOGGING方式执行。

比如,我们来看一个在SQL语句中添加NOLOGGING选项的例子,数据库运行在归档模式下。
SQL> select value from v$mystat a,v$statname b
2 where a.statistic#=b.statistic# and b.name='redo size';
VALUE
----------
10592
SQL
> create table t1 as select * from dba_objects;
SQL
> select value from v$mystat a,v$statname b
2 where a.statistic#=b.statistic# and b.name='redo size';
VALUE
----------
5796480
很明显的,正常情况下创建表时生成了5785888(5796480-10592)字节,也就是约5.5M的重做记录。
SQL> drop table t1;
SQL
> select value from v$mystat a,v$statname b
2 where a.statistic#=b.statistic# and b.name='redo size';
VALUE
----------
5801424
 SQL> create table t1 NOLOGGING as select * from dba_objects;
SQL
> select value from v$mystat a,v$statname b
2 where a.statistic#=b.statistic# and b.name='redo size';
VALUE
----------
5909952
 
    可以看到,当使用NOLOGGING选项创建表时,只生成了108528(5909952-5801424)字节,也就是约106K的重做记录。原来生成 的大约5.5M日志就是表t1本身的容量,而使用NOLOGGING以后,直接写入磁盘,没有对表t1自身的数据记录日志,所生成的106K的重做记录只 是在创建表时,对所修改的数据字典的保护。不过这里要注意一个问题,就是我们的测试环境是归档模式,如果在非归档模式下,则对CTAS命令使用 NOLOGGING选项所产生的日志与不使用NOLOGGING选项所产生的日志几乎没有差别。这是因为非归档模式下的CTAS命令本身就不会对所创建的 表的数据记录日志。
现在我们来测试一下在非归档模式下,使用NOLOGGING选项来定义索引时的情况。
SQL> select index_name,logging from user_indexes where table_name='T1';
INDEX_NAME
LOG
------------------------------ ---
IDX_T1_OBJECTNAME YES
SQL
> select value from v$mystat a,v$statname b
2 where a.statistic#=b.statistic# and b.name='redo size';
VALUE
----------
4170024
SQL
> alter index idx_t1_objectname rebuild;
SQL
> select value from v$mystat a,v$statname b
2 where a.statistic#=b.statistic# and b.name='redo size';
VALUE
----------
6257600
可以看到,正常重建索引时生成了2087576(
6257600-4170024)字节,也就是大约2M的重做记录。
SQL
> alter index idx_t1_objectname nologging;
SQL
> select value from v$mystat a,v$statname b
2 where a.statistic#=b.statistic# and b.name='redo size';
VALUE
----------
6259968
SQL
> alter index idx_t1_objectname rebuild;
SQL
> select value from v$mystat a,v$statname b
2 where a.statistic#=b.statistic# and b.name='redo size';
VALUE
----------
6325568
将索引定义为NOLOGGING以后,再次rebuild只生成了65600(6325568-6259968)字节,也就是64K的重做记录。注意,这 是在非归档模式下的测试结果。可以看到这与CTAS创建表有所不同,CTAS在非归档模式下不会记录数据的变化,只会记录数据字典的变化。而在非归档模式 下创建索引时,如果不使用NOLOGGING选项,则既会记录数据字典的变化,也会记录索引数据块的变化。
现在,我们将前面那个CTAS例子中(归档模式下)的当前的联机日志文件(含有用NOLOGGING选项创建表t1的重做记录)转储出来看看这时的重做记 录是怎样的。我们找到表t1对应的object id为51535,然后对转储出来的日志文件进行搜索,可以发现很多类似下图五这样的内容,这部分内容表示对数据字典的修改所生成的重做记录。

图五
我们同时还会发现很多类似下图六的内容,这部分内容就说明为何使用了append以后,并没有修改数据字典,为何还是产生了大约106K的重做记录的原因。不管使用NOLOGGING还是append,都会对所修改

图六
的数据块进行标记,标记这些数据块已经出现软损坏(soft-corrupt)了,在恢复是不能使用。这时改动向量的类型是INVLD。同时会记录起始数 据块的地址(下图的DBA:0X1000114),以及后面有多少个数据块(下图的BLKS:0x0005)被标记为损坏。当使用这样的重做记录进行恢复 时,系统会报ORA-273错误。
阅读(928) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~