ORACLE DataGuard Logical Standby 详解之:(五)修改逻辑Standby端数据

本节内容

相对物理Standby,逻辑Standby的管理要复杂一点点。这个就是管理一个半数据库和管理两个数据库的差异(假设Data Guard环境为一主一备的情况下),毕竟逻辑Standby只是逻辑上,仿佛与Primary数据库一致,其实它是一个独立运行的,甚至可能与Primary数据库完全不同的数据库系统,对于这种配置环境,管理上多花点工夫想想也是应该的。

1 指定对象跳过应用
在默认情况下,接收自Primary的REDO数据中,所有能够被逻辑Standby数据库支持的操作都会在逻辑Standby端执行。如果你希望跳过对某些对象的某些操作的话,DBMS_LOGSTDBY.SKIP就能派上用场了。

先来看看DBMS_LOGSTDBY.SKIP的语法:
DBMS_LOGSTDBY.SKIP (
stmt IN VARCHAR2,
schema_name IN VARCHAR2 DEFAULT NULL,
object_name IN VARCHAR2 DEFAULT NULL,
proc_name IN VARCHAR2 DEFAULT NULL,
use_like IN BOOLEAN DEFAULT TRUE,
esc IN CHAR1 DEFAULT NULL);
除stmt外,其他都是可选参数,并且看字面意义就能明白其所指。例如,你想跳过SCOTT用户下对dept表的DML操作,可以通过执行下列语句实现(执行该过程前需要先停止REDO应用):
SQL> ALTER DATABASE STOP LOGICAL STANDBY APPLY;
Database altered.
SQL> EXEC DBMS_LOGSTDBY.SKIP(‘DML’, ‘SCOTT’, ‘DEPT’);
PL/SQL procedure successfully completed.
SQL>ALTER DATABASE START LOGICAL STANDBY APPLY IMMEDIATE;
Database altered.

2 恢复对象同步
如果逻辑Standby中的某些表取消了与Primary的同步维护,现在希望再恢复同步,没问题,DBMS_LOGSTDBY家大业大,它还有个叫UNSKIP的门生专干这个。
我们来看一下DBMS_LOGSTDBY.UNSKIP的语法:
DBMS_LOGSTDBY.UNSKIP (
stmt IN VARCHAR2,
schema_name IN VARCHAR2,
object_name IN VARCHAR2);
三项均为必选参数,各参数的定义与SKIP过程相同。

下面演示恢复tmp1表的同步。
首先查看当前逻辑Standby都有哪些对象处于不同步状态,可以通过DBA_LOGSTDBY_SKIP视图查看,例如:
SQL> select * from dba_logstdby_skip;
ERROR STATEMENT_OPT OWNER NAME U E PROC

N DML SCOTT DEPT Y
N INTERNAL SCHEMA SYSTEM % Y
N INTERNAL SCHEMA SYS % Y
N INTERNAL SCHEMA OLAPSYS % Y
N INTERNAL SCHEMA SI_INFORMT % Y
N INTERNAL SCHEMA MGMT_VIEW % Y
N INTERNAL SCHEMA ORDPLUGINS % Y
N INTERNAL SCHEMA XDB % Y
N INTERNAL SCHEMA SYSMAN % Y
N INTERNAL SCHEMA WMSYS % Y
N INTERNAL SCHEMA DBSNMP % Y

注意在执行DBMS_LOGSTDBY.UNSKIP过程前,要停止当前的SQL应用状态:
SQL> ALTER DATABASE STOP LOGICAL STANDBY APPLY;
Database altered.
执行DBMS_LOGSTDBY.UNSKIP过程,恢复前面停止的scott.tmp1表的应用:
SQL> execute dbms_logstdby.unskip(‘DML’, ‘SCOTT’, ‘dept’);
PL/SQL procedure successfully completed.

3 添加或重建对象
指定对象跳过应用虽然被取消,但是有可能在此期间由于Primary数据库做过数据修改,两端此时已经不同步,如果Standby端继续应用极有可能导致应用错误的数据。
对于这类情况,Oracle也早有预见,DBMS_LOGSTDBY包中还有一个过程叫INSTANTIATE_TABLE,专门用来同步一下跳过的对象,以保持与Primary数据库的一致。

DBMS_LOGSTDBY.INSTANTIATE_TABLE的调用语法如下:
DBMS_LOGSTDBY.INSTANTIATE_TABLE (
schema_name IN VARCHAR2,
table_name IN VARCHAR2,
dblink IN VARCHAR2);
除了SCHEMA名称和表名称外,还需要提供一个数据库链,因此这里我们首先在逻辑Standby端创建一个连接Primary数据库的数据库链:
SQL> CREATE DATABASE LINK PRE_TBL_DATA CONNECT TO SYSTEM IDENTIFIED BY ADMIN
USING ‘ORCL_PD’;
Database link created.
执行使用DBMS_LOGSTDBY.INSTANTIATE_TABLE过程,重新同步SCOTT.TMP1表(注意执行该过程前别忘了暂停当前的SQL应用):
SQL>EXEC DBMS_LOGSTDBY.INSTANTIATE_TABLE(‘SCOTT’, ‘DEPT’, ‘PRE_TBL_DATA’);
PL/SQL procedure successfully completed.
SQL> SELECT * FROM SCOTT.DEPT;

对象已被重建,然后重新启动SQL应用即可:
SQL> ALTER DATABASE START LOGICAL STANDBY APPLY IMMEDIATE;
Database altered.

4 逻辑Standby端修改数据
逻辑Standby的一个极具实用价值的特性就是可以边查询边应用,因此将其作为报表服务器专供查询是个很不错的想法,而且逻辑Standby相对于物理Standby而言更具灵活性,如我们可以在逻辑Standby上,对一些表创建Primary数据库并不方便创建的索引、约束,甚至可以做DML/DDL操作(当然,需要注意不要破坏了与Primary数据库之间同步的逻辑关系)。
不过由于此时Data Guard仍然控制着对逻辑Standby数据库中表的读写操作,因此,如果你想对逻辑Standby中的数据做些什么的话,ALTER SESSION DISABLE|ENABLE GUARD语句就必须牢记在心了,它拥有像”芝麻开门”一样神奇的能力。 下面我们就来感受一下吧。

在逻辑Standby端启动SQL应用的情况下,执行DDL操作:
SQL> GRANT DBA TO SCOTT;
Grant succeeded.
SQL> CONN SCOTT/TIGER;
Connected.
SQL> CREATE TABLE DAVE AS SELECT * FROM USER_OBJECTS;
CREATE TABLE DAVE AS SELECT * FROM USER_OBJECTS
*
ERROR at line 1:
ORA-01031: insufficient privileges

出错了,提示权限不足,实际上SCOTT被授予了DBA角色,肯定拥有CREATE TABLE权限的,因此此处与用户的权限无关,而是有其他因素制约了SCOTT无法进行修改。
下面禁用Data Guard保护之后,再次尝试操作数据:
SQL> ALTER SESSION DISABLE GUARD;
Session altered.
SQL> CREATE TABLE DAVE AS SELECT * FROM USER_OBJECTS;
Table created.
这下可以了,这就是Data Guard的作用。
注 意: 数据修改完之后,别忘了再次启用Data Guard,以避免不经意的误操作对逻辑Standby的配置造成影响��你说不手动启用Data Guard保护,直接退出行不行,当然也可以,ALTER SESSION所做修改仅对当前会话有效,退出重新登录,原会话设置自然就失效了)。
SQL> ALTER SESSION ENABLE GUARD;
Session altered.

按照Oracle的建议,还是尽可能不要在逻辑Standby端执行DML之类操作,以免破解其与Primary之间同步的逻辑关系,

也可以通过下列语句查看当前数据库是否处于Data Guard保护状态:
SQL> SELECT GUARD_STATUS FROM V$DATABASE;

ALL

该参数对应三个值:
ALL:表示对数据库中所有对象启动修改保护,除SYS用户外,其他用户均不能直接修改数据。
STANDBY:表示对处于逻辑Standby维护关系的对象启动修改保护,除SYS用户外,其他用户均不能直接修改数据。
NONE:不启动数据保护。

如果要永久设置数据库的Data Guard保护模式,则是通过ALTER DATABASE命令来完成,可指定的值也正是上述的三种,例如:
SQL> ALTER DATABASE GUARD STANDBY;
Database altered.

执行完上述语句后,Data Guard仅对处于逻辑Standby维护关系的对象进行防止修改操作的保护。

考虑到逻辑Standby中也有可能对数据进行修改(正如上例演示),因此这里引申谈一谈在逻辑Standby数据库中,约束和触发器的执行模式。默认情况下,约束和触发器都能在逻辑Standby端正常运行。约束和触发器在逻辑Standby端的执行可以分成两种情况:
对于SQL应用维护的约束和触发器,由于在Primary数据库已经检查过约束,因此Standby端不需要再次检查;触发器的情况也是这样,Primary端操作时结果已经被记录,因此逻辑Standby端将直接被应用,而不会二次触发。
对于没有SQL应用维护的约束和触发器,其执行情况与普通的Oracle数据库环境相同。

5 重定义REDO应用执行的操作
对于逻辑Standby数据库,你甚至可以通过编写自定义的PROCEDURE,来重新定义SQL应用时执行的操作。
如逻辑Standby数据库的文件路径与Primary数据库路径不同,如果是物理Standby,可以通过*_FILE_NAME_CONVERT之类的参数处理,在逻辑Standby环境中这几个参数无效,应该如何处理呢?答案就是通过编写自定义的过程,修改SQL应用时执行的操作。

下面通过示例,演示通过编写自定义的PROCEDURE,修改创建表空间时逻辑Standby端数据文件的路径。
首先当然是创建一个过程,建议创建在SYS下,因为在这个用户下的操作肯定不会有同步的问题,如下所示:
SQL> CREATE OR REPLACE PROCEDURE SYS.HANDLE_TBS_DDL (
2 OLD_STMT IN VARCHAR2,
3 STMT_TYP IN VARCHAR2,
4 SCHEMA IN VARCHAR2,
5 NAME IN VARCHAR2,
6 XIDUSN IN NUMBER,
7 XIDSLT IN NUMBER,
8 XIDSQN IN NUMBER,
9 ACTION OUT NUMBER,
10 NEW_STMT OUT VARCHAR2
11 ) AS
12 BEGIN
13
14 NEW_STMT := REPLACE(OLD_STMT, ‘/u01/oradata/orcl_pd/’, ‘/u01/oradata/orcl_st’);
15 ACTION := DBMS_LOGSTDBY.SKIP_ACTION_REPLACE;
16
17 EXCEPTION
18 WHEN OTHERS THEN
19 ACTION := DBMS_LOGSTDBY.SKIP_ACTION_ERROR;
20 NEW_STMT := NULL;
21 END HANDLE_TBS_DDL;
22 /
Procedure created.
逻辑非常简单,基本上就是一个REPLACE,不过PROCEDURE中声明的变量看起来很多,这个是固定格式,不建议修改。

停止逻辑Standby的SQL应用:
SQL> ALTER DATABASE STOP LOGICAL STANDBY APPLY;
Database altered.

如果不停,PROCEDURE不能生效。

执行DBMS_LOGSTDBY.SKIP过程,将编写的过程注册到表空间处理的SQL应用中:
SQL> EXEC DBMS_LOGSTDBY.SKIP (stmt => ‘TABLESPACE’,proc_name => ‘sys.handle_tbs_ddl’);
PL/SQL procedure successfully completed.

这里也要借助DBMS_LOGSTDBY.SKIP过程实现。该过程功能非常强大,而且操作非常灵活。

重启SQL应用:
SQL> ALTER DATABASE START LOGICAL STANDBY APPLY IMMEDIATE;
Database altered.

测试一下,在Primary端创建一个新的表空间:
SQL> CREATE TABLESPACE BOOKS DATAFILE ‘/u01/oradata/orcl_pd/books01.dbf’ SIZE 20m;
Tablespace created.
SQL> SELECT FILE_NAME FROM DBA_DATA_FILES WHERE TABLESPACE_NAME=’BOOKS’;

/u01/oradata/orcl_pd/books01.dbf

转向逻辑Standby数据库查看:
SQL> SELECT FILE_NAME FROM DBA_DATA_FILES WHERE TABLESPACE_NAME=’BOOKS’;

/u01/oradata/orcl_st/books01.dbf
表空间成功创建,并且数据文件路径也被转换为我们指定的路径。

此时如果你查看Alert日志文件,会发现其中记录下了类似这样的信息:
LOGSTDBY stmt: create tablespace books datafile ‘/u01/oradata/orcl_pd/books01.dbf’ size 20m
LOGSTDBY status: ORA-16110: 逻辑备用应用 DDL 的用户过程处理
LOGSTDBY id: XID 0x0001.009.000000d1, hSCN 0x0000.0012ec41,
lSCN 0x0000.0012ec41, Thread 1, RBA 0x007f.0000079a.80,
txnCscn 0x0000.0012ec43, PID 5816, ORACLE.EXE (P004)
LOGSTDBY stmt: create tablespace books datafile ‘/u01/oradata/orcl_st/books01.dbf’ size 20m
LOGSTDBY status: ORA-16202: 跳过过程已请求替换语句
LOGSTDBY id: XID 0x0001.009.000000d1, hSCN 0x0000.0012ec41,
lSCN 0x0000.0012ec41, Thread 1, RBA 0x007f.0000079a.80,
txnCscn 0x0000.0012ec43, PID 5816, ORACLE.EXE (P004)
create tablespace books datafile ‘/u01/oradata/orcl_st/books01.dbf’ size 20m
Completed: create tablespace books datafile ‘/u01/oradata/orcl_st/books01.dbf’ size 20m
LOGSTDBY stmt: create tablespace books datafile ‘/u01/oradata/orcl_st/books01.dbf’ size 20m
LOGSTDBY status: ORA-16204: 成功应用了 DDL


数据运维技术 » ORACLE DataGuard Logical Standby 详解之:(五)修改逻辑Standby端数据