3.4减少生成的重做记录的方法
要优化日志缓冲区的使用,最直接、最容易看到效果的方法当然就是阻止重做记录的产生了。也就是说对DML语句不记录数据块的改变过程,从而减少对日志缓冲区的使用。但是,毫无疑问,这完全违背了oracle设立日志缓冲区以及联机日志文件的目的。由于没有产生对数据块变化的记录,那么如果数据库发生崩溃,将导致无法恢复到数据库崩溃前一秒的状态,也就必然发生数据丢失。
通过使用NOLOGGING短语或者append提示来阻止重做记录的产生。该短语可以用在表空间上,表示该表空间里的对象缺省都不产生日志。也可以将表或者索引定义为NOLOGGING,这样该表上的DML操作都不生成重做记录,而对索引的重建也不生成重做记录。还可以直接用在以下的SQL语句中:
<!--[if !supportLists]-->1) <!--[endif]-->直接路径装载(Direct Loader)以及直接路径插入(对insert使用append提示:insert /*+ append*/)。
<!--[if !supportLists]-->2) <!--[endif]-->create table table-name NOLOGGING as select …(CTAS)
<!--[if !supportLists]-->3) <!--[endif]-->alter table table-name NOLOGGING move tablespace tablespace-name
<!--[if !supportLists]-->4) <!--[endif]-->create index index-name NOLOGGING …
<!--[if !supportLists]-->5) <!--[endif]-->alter index index-name NOLOGGING rebuild…
<!--[if !supportLists]-->6) <!--[endif]-->分区操作中,可以添加NOLOGGING短语。
<!--[if !supportLists]-->7) <!--[endif]-->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错误。
4.归档
当一个联机日志文件写完,发生日志切换,切换到另一个日志文件时,可以选择将前一个写完的联机日志文件进行归档。归档的过程简单理解就是拷贝的过程,将前一个联机日志文件完整拷贝到指定的地方。这样的话,每次一个联机日志文件写完以后就生成一个拷贝出来,从而可以使得自设置归档以来数据库所发生的所有的数据块变化都被记录下来。从而为数据恢复提供了完备的基础,你可以将数据库恢复到任意你希望的时间点。不过设置归档需要比不设置归档消耗更多的磁盘空间,同时会一定程度上降低系统的性能,因为毕竟多了一块写磁盘的工作。但是,这部分性能的损失一方面相对数据安全性来说,完全可以忽略;另一方面,这部分的性能损失本身不会对系统产生很大的影响,而且可以通过一些方式将归档所带来的性能损失降低到最低。
如果设置了归档模式,那么当一个联机日志文件文件还没有完成归档时,是不能被重用的。也就是说,假设只有两组归档日志(A和B),假设A写完以后,切换到B以后,B也很快写完,这时又切换回A时,发现A仍然还处于归档过程中,这时LGWR进程必须等待,而触发LGWR的用户进程也必须等待。其等待事件为log file switch (archiving needed)。这时整个数据库都停住了。
归档主要是通过ARCH进程来完成的,只有将数据库设置为archivelog模式时,oracle才会启动ARCH进程。设置归档模式时,先启动数据库到mount模式,然后发出alter database archivelog就可设置数据库为归档模式。同时发出命令:archive log start或者设置初始化参数log_archive_start为true时,表示系统自动进行归档,否则需要手工归档。ARCH进程在以下条件下触发:
<!--[if !supportLists]-->1) <!--[endif]-->如果设置了自动归档模式,则日志切换时,由LGWR进程触发ARCH进程进行归档。这是最常见的方式。
<!--[if !supportLists]-->2) <!--[endif]-->可以手工进行归档。使用命令:alter system archive log current表示启动ARCH进程,从而对当前的日志文件进行归档。
<!--[if !supportLists]-->3) <!--[endif]-->如果ARCH进程在5分钟以后还没有接收到LGWR的通知,则发生超时,于是ARCH被唤醒以检查是否存在需要归档的日志文件。ARCH通过读取控制文件中的信息来决定是否需要归档以及应该归档哪些日志文件。但是在进行实例恢复或者介质恢复的过程中,ARCH进程不会启动。
通常来说,ARCH进程启动以后的处理过程包括:
<!--[if !supportLists]-->1) <!--[endif]-->从控制文件中读取未归档的日志文件。注意,可能会有多个日志文件。
<!--[if !supportLists]-->2) <!--[endif]-->在内存中分配归档日志块,归档日志块的个数由隐藏参数_log_archive_buffer确定;每个归档日志块的大小则由_log_archive_buffer_size确定。
<!--[if !supportLists]-->3) <!--[endif]-->打开联机归档日志组中的所有的日志文件,并校验它们的文件头。
<!--[if !supportLists]-->4) <!--[endif]-->搜索可用的归档目的地。
<!--[if !supportLists]-->5) <!--[endif]-->在可用的归档目的地创建并打开归档日志文件。
<!--[if !supportLists]-->6) <!--[endif]-->在日志文件中从头到尾进行循环,取出每个日志块,并放入内存中的归档日志块,然后按照SCN的顺序放入归档日志文件中。
<!--[if !supportLists]-->7) <!--[endif]-->关闭所有打开的文件,包括联机日志文件和归档日志文件。
在ARCH进程将联机日志文件里的日志块读取到归档日志块里的时候,如果发现所读取的日志块发
生损坏,则会转到相同日志组中的另外一个日志文件去读取相同的日志块。如果相同日志组中的所有日志文件的该日志块都发生损坏,则ARCH进程报错,无法继续进行归档工作。
当ARCH进程从日志文件中成功读取一个日志块以后,为了平衡物理I/O,ARCH进程会转到相同日志组中的另外一个日志文件读取下一个日志块。如此这般,在日志组中的每个日志文件之间进行循环读取。
如果ARCH进程出现性能问题,最突出的表现就是log file switch(archiving needed)等待事件的等待次数和等待时间很长。我们先来模拟一下该等待事件。这里要说明一下,在设置手动归档时,10g以前都只要archive log stop就可以了。10g以后必须使用alter database archivelog manual命令。
SQL> startup mount;
SQL> alter database archivelog manual; --设置手动归档,不启用自动归档
SQL> alter database open;
SQL> select distinct sid from v$mystat;
SID
----------
159
SQL> insert into hanson.t1 select * from dba_objects;
这时,该语句停住了,然后我们再开一个session,看看该session在等待什么事件。
SQL> select event from v$session_wait where sid=159;
EVENT
----------------------------------------------------------------
log file switch (archiving needed)
可以看到,该进程正是在等待log file switch(archiving needed)事件。
调优ARCH时,可以从以下几个方面入手。
<!--[if !supportLists]-->1) <!--[endif]-->确定是否启用了自动归档,如果没有启用自动归档,则必须定期手工归档。
<!--[if !supportLists]-->2) <!--[endif]-->需要确保归档日志文件不应该与联机归档日志文件放在同一个磁盘阵列里,而应该单独存放。同时避免把归档日志文件放在RAID-5设备上。
<!--[if !supportLists]-->3) <!--[endif]-->把联机日志文件设置大一些,以便给ARCH进程的归档工作留出足够的时间。
<!--[if !supportLists]-->4) <!--[endif]-->应该检查一下归档路径的设置,如果设置了很多的归档路径,则可以考虑减少一些归档路径。
<!--[if !supportLists]-->5) <!--[endif]-->如果ARCH进程的速度还是很慢,则可以考虑增加ARCH进程的数量。可以设置的最大数量随oracle版本的不同而不同,9i下可以设置10个,而10g下可以设置30个。初始化参数log_archive_max_processes决定了最多能够启动多少个ARCH进程。当LGWR进程发现当前的ARCH进程的数量不足以支持当前的负载时会自动启动一个新的ARCH进程。LGWR每次启动一个新的ARCH进程时都会将该信息记录在日志文件里。但是这里要说明的是,并不是说多个ARCH进程可以同时读取同一组联机日志文件并对其规定,而是说次只能有一个ARCH进程来读取联机日志文件并将其归档到不同的归档路径下。因此假设4组联机日志文件,依次为A、B、C、D。同时定义log_archive_max_processes为3,也就是最多能够启动3个ARCH进程,假设分别为1#、2#、3#。那么当A写完,发生日志切换,切换到B时,LGWR启动1# ARCH进程对A进行归档。假设B也写完了,再次发生日志切换,切换到C时,这时ARCH 1#还没完成归档,这时LGWR发现这个情况,于是启动2# ARCH进程对B进行归档。假设这时C也写完了,再次发生日志切换,切换到D时,如果这时1# ARCH进程已经完成了对A的归档,则LGWR启动1# ARCH来对C进行归档,如果这时1# ARCH仍然没有完成,则LGWR会启动3# ARCH对C进行归档。从这里我们已经可以看到,通常情况下,log_archive_max_processes的缺省值就够用了。如果将要发生很大量的数据库批量写入以及更新等操作,则说明可能在很短时间内涌入大量的重做记录,可能日志切换的速度会比ARCH进行归档的速度,这个时候,可以设置log_archive_max_processes为一个更大的值,等到批量写入完成以后,再将该参数设置回缺省值。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/751371/viewspace-567584/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/751371/viewspace-567584/