1、首先是加快主库的更新操作,那么首先关闭主库对STANDBY的归档,减少主库写STANDBY库日志对主库产生的压力 ,这需要在更新开始前在主库设置log_archive_dest_state_N参数为DEFER ,然后主库切换日志来激活这个新的参数设置。注意:如果是RAC的主库,则每个库都需要设置此参数,并且每个库都进行一次日志切换操作。
2、主库更新完成后,可以在备用库做一些设置来加速日志应用的更新 ,参数如下:
APPLY_SERVERS=16--可以设置更多的并行应用的进行来提高应用的速度
PREPARE_SERVERS=8--可以设置更多的准备进程来提高应用速度
MAX_SERVERS=40--设置最大可使用的进程数,要大于所有的APPLY、PREPARE、ANALYZE等进程之和
----设置以上并行参数的时候,要注意PARAMETER中的PARALLEL参数相关的设置也要能支持上面的调整。
_EAGER_SIZE=4001--这个是一个隐含的参数,用来设置大事务和小事务时间的分界线,更新记录行数大于此值的被认为是大事务,提高这个参数 的设置对大事务的应用有提高。查询 v$logstdby_stats视图,如果没有很多的bytes paged out的话,说明这个参数还可以设置的更大。
MAX_SGA=2048--LCR可使用的SGA大小,如果过小则会产生很多的PAGE OUT,可以调整此SGA的大小,此SGA是数据SHARED POOL中的一部分的,所以要保证SHARED POOL也足够大
PRESERVE_COMMIT_ORDER = FALSE--设置事务不按照严格的主库上事务发生的顺序来进行应用,也可以提高应用的速度。
3、如果以上招数都不能解决问题,那可能就是碰到了ORACLE的BUG了,参考5327658.8,上面说到如果更新百万级大表的话,可能造成STANDBY的应用非常慢,可以通过升级来解决问题,需要升级到10.2.0.4或者11.1.0.6 。
4、我这次千万级的更新使用了2的方法后,还是应用很慢,整整一天应用都没有同步过来,后来发现可以把一个表的DML操作SKIP掉,然后重新同步这个表来实现 。 于是先使用dbms_logstdby.skip把这个表所有的DML操作全部忽略,加速应用,等到积累的日志全部应用完成后,使用 dbms_logstdby.instantiate_table进行表的同步,结果发现这个同步操作也是很慢,半个多小时了还是在进行中,于是取消操 作。后来发现dbms_logstdby.instantiate_table基本上就是在STANDBY库先把表删除,然后再使用IMPDP把这个表的 数据通过DBLINK导过来。既然这样可以,那就手工做吧。
5、把STANDBY的APPLY停下来,然后查询STANDBY的 V$LOGSTDBY_PROGRESS , 得到当前的APPLY_SCN,那么利用主库的FLASHBACK特性,先把STANDBY的表 TRUNCATE掉,然后使用INSERT /*+ APPEND*/ INTO TABLE SELECT * FROM TABLE@DBLINK AS SCN OF XX把数据导过来,其中的XX就是上面查到的APPLY_SCN。这当中其实就是大家很熟悉的导数据操作了,可以使用先删除索引,导入完了再重建,使用 APPEND提示等等多种手段来提高导入的速度。
6、经过10多分钟,数据导完,建完索引,整个过程不到半个小时,比dbms_logstdby.instantiate_table还快一些,虽然繁琐,但是过程比较透明,出现问题也容易处理的多。
建议和总结 :
1、方法2中的很多参数在平时的日志应用中就可是设置好来加速日志应用速度。
2、对于大批量的数据更新,尽量使用分批提交的方式,把大事务拆分成小的事务,而且进行要比_EAGER_SIZE参数设置的要小一些
3、PRESERVE_COMMIT_ORDER参数在日志同步完成后,为了保证事务和生产上的顺序一致,最好把这个参数使用DBMS_LOGSTDBY.APPLY_UNSEGT取消。
4、因为主库的一个DML的操作在STANDBY库会被分解成一个个单独的更新的sql,所以可以合理利用规则来SKIP这些DML,然后再手工同步的方式来进行
5、有可能的话,升级数据库系统
参考至:http://www.eygle.com/digest/2009/02/logical_standby_slowly_hang.html
如有错误,欢迎指正
邮箱:czmcj@163.com