2013年(350)
分类: Oracle
2013-04-25 10:04:50
修改逻辑standby端数据
我们前面提到,逻辑standby一个极具实用价值的特性即是可以边查询边应用,因此将其做为报表服务器专供查询是个很不错的想法,而且逻辑standby相对于物理standby而言更具灵活性,比如我们可以在逻辑standby上,对一些表创建primary库上并不方便创建的索引,约束,甚至可以做dml,ddl操作(当然,需要注意不要破坏了与primary之间同步的逻辑关系)。不过由于此时dg仍然控制着对逻辑standby表的读写操作,因此,如果你想对逻辑standby中的数据做些什么的话,alter session database disable|enable guard语句就必须牢记在心了,它拥有像“芝麻开门”一样神奇的能力,不信?下面我们就来感受一下吧。
1、逻辑standby端执行ddl
在逻辑standby端开始了redo应用的情况下,执行ddl操作:
JSSLDG2> create table tmp55 as select * From b;
create table tmp55 as select * From b
*
第 1 行出现错误:
ORA-01031: 权限不足
看看,出错了吧~~~
JSSLDG2> alter session disable guard;
会话已更改。
JSSLDG2> create table tmp55 as select * From b;
表已创建。
只有关闭了guard保护之后,才能操作数据,然后别忘了再启用guard,以避免不经意的操作对逻辑standby的配置造成影响。
JSSLDG2> alter session enable guard;
会话已更改。
提示:建议还是尽可能不要在逻辑standby执行执行dml之类操作,以免破解其与primary之间同步的逻辑关系,当然,这只是个建议,如果你已经仔细看完了3.1章,并且对表结构及存储结构了如指掌,那您就爱干嘛爱嘛。
2、取消对象同步
如果说,某些表或者数据不需要保护(比如一些在逻辑standby端生成的统计表),这个时候就需要DBMS_LOGSTDBY.SKIP,前头已经介绍过了dbms_logstdby.skip的基本用法,下面我们来具体演示一下!
下面我们假设standby端有一批表名为tmp开头的表,这张表不再需要保持与primary的同步,那么按照步骤执行下列语句,应用即可跳过这些表:
老规矩,先停了redo应用
JSSLDG2> alter database stop logical standby apply;
数据库已更改。
JSSLDG2> execute dbms_logstdby.skip('SCHEMA_DDL','JSS','TMP%');
--跳过对象的ddl操作
PL/SQL 过程已成功完成。
JSSLDG2> execute dbms_logstdby.skip('DML','JSS','TMP%');
--跳过对象的dml操作
PL/SQL 过程已成功完成。
JSSLDG2> ALTER DATABASE START LOGICAL STANDBY APPLY IMMEDIATE;
数据库已更改。
注意其中的%,该符号为通配符,作用与在sql语句中的相同。
OK,下面来测试一下,先看看逻辑standby中表的信息,我们选择两张表,一张是我们前面已经指定了跳过的表tmp1,另一张是普通表b:
JSSLDG2> select max(aa) from jss.tmp1;
Max(aa)
--------------------
h
JSSLDG2> select max(id) from jss.b;
Max(id)
----------
9
JSSLDG2> select sequence#,applied from dba_logstdby_log;
SEQUENCE# APPLIED
---------- --------
872 YES
然后在primary数据库执行插入操作
JSSWEB> select max(aa) from jss.tmp1;
Max(aa)
--------------------
h
JSSWEB> insert into jss.tmp1 values ('i');
已创建 1 行。
JSSWEB> insert into jss.b values (10);
已创建 1 行。
JSSWEB> commit;
提交完成。
JSSWEB> alter system switch logfile;
系统已更改。
JSSWEB> select max(sequence#) from v$archived_log;
MAX(SEQUENCE#)
--------------
873
再来看看逻辑standby端的同步情况:
JSSLDG2> select sequence#,applied from dba_logstdby_log;
SEQUENCE# APPLIED
---------- --------
873 YES
显然日志已经接收,再看看数据:
JSSLDG2> select max(id) from b;
Max(id)
----------
10
JSSLDG2> select max(aa) from jss.tmp1;
Max(aa)
--------------------
h
b表已应用,而tmp1表则无变化。
3、恢复对象同步
如果说某些表某个时候取消了同步,现在希望再恢复同步,没问题,DBMS_LOGSTDBY家大业大,它还有个叫UNSKIP的门生就是专干这个的。
我们来看一下dbms_logstdby.unskip的语法:
DBMS_LOGSTDBY.UNSKIP (
stmt IN VARCHAR2,
schema_name IN VARCHAR2,
object_name IN VARCHAR2);
三项均为必选参数,各参数的定义与skip过程相同,这里不再复述。
此处我们来演示恢复tmp%表的同步。
JSSLDG2> select *from dba_logstdby_skip;
ERROR STATEMENT_OPT OWNER NAME U E PROC
----- --------------- ---------- --------------- - - --------------------
N SCHEMA_DDL JSS TMP% Y
N DML JSS TMP% Y
N DML JSS TMP1 Y
........
JSSLDG2> alter database stop logical standby apply;
数据库已更改。
JSSLDG2> execute dbms_logstdby.unskip('DML','JSS','TMP1');
--本步操作是为解决历史遗留问题,不用关注
PL/SQL 过程已成功完成。
JSSLDG2> execute dbms_logstdby.unskip('DML','JSS','TMP%');
PL/SQL 过程已成功完成。
JSSLDG2> execute dbms_logstdby.unskip('SCHEMA_DDL','JSS','TMP%');
PL/SQL 过程已成功完成。
跳过同步已经取消了,紧接着我们需要再调用dbms_logstdby.instantiate_table过程重新同步一下跳地的对象,将skip这段时间,primary对tmp1表所做的操作同步过来(就俺看来,instantiate_table过程实际上是借助dblink重建了一遍对象),以保持与primary的一致。Dbms_logstdby.instantiate_table的语法如下:
DBMS_LOGSTDBY.INSTANTIATE_TABLE (
schema_name IN VARCHAR2,
table_name IN VARCHAR2,
dblink IN VARCHAR2);
使用DBMS_LOGSTDBY.INSTANTIATE_TABLE过程重新执行一下同步(执行前别忘了暂停redo应用):
JSSLDG2> EXECUTE DBMS_LOGSTDBY.INSTANTIATE_TABLE('JSS','TMP1','GETJSSWEB');
PL/SQL 过程已成功完成。
JSSLDG2> select *from jss.tmp1;
AA
--------------------
a
b
c
d
e
f
g
h
i
已选择9行。
数据已重建,下面测试一下该表的redo应用是否恢复了。
JSSWEB> insert into jss.tmp1 values ('j');
已创建 1 行。
JSSWEB> insert into jss.tmp1 values ('k');
字数受限,详细请查看: