ORACLE 11G 之DATAGUARD搭建逻辑standby
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
Oracle Data Guard逻辑备库是利用主库的一个备份首先建立一个物理备库,然后再将其转换为逻辑备库。这之后主库将日志传递到备库,备库利用logminer从主库的日志中解析出主库所执行过的SQL,在备库上重新执行一遍,从而保证与主库的数据在逻辑上保持一致。与物理备库相对应的是,物理备库使用的是redo apply,逻辑备库使用的是sql apply。因此逻辑备库仅仅保证数据与主库是在逻辑上是一致的,从而逻辑备库可以处于open状态下并进行相应的DML操作。
在转换physical备库到logical备库之前,先来看看主备库的情况:
SQL> select name,open_mode,database_role,protection_mode from v$database;
- Primary库
Physical备库
1.1 Step-by-Step Instructions for Creating a Logical Standby Database
由于逻辑Standby是通过SQL应用来保持与Primary数据库的同步。SQL应用与REDO应用是有很大的区别,REDO应用实际上是在物理Standby端进行RECOVER;SQL应用则是分析重做日志文件中的REDO信息,并将其转换为SQL语句,在逻辑Standby端执行,因此需要确认操作的对象和语句是否能被逻辑Standby支持。
- 检查primary数据库是否有不被逻辑standby支持的对象
SQL> SELECT * FROM DBA_LOGSTDBY_UNSUPPORTED;
- 查看primary数据库中不含有主键或唯一键索引的表
SQL> SELECT OWNER, TABLE_NAME FROM DBA_LOGSTDBY_NOT_UNIQUE 2> WHERE (OWNER, TABLE_NAME) NOT IN 3> (SELECT DISTINCT OWNER, TABLE_NAME FROM DBA_LOGSTDBY_UNSUPPORTED) 4> AND BAD_COLUMN = 'Y';
注意BAD_COLUMN列值,该列有两个值:
Y :表示该表中有采用大数据类型的字段,比如LONG啦,CLOB啦之类。如果表中除log列某些行记录完全匹配,则该表无法成功应用于逻辑standby。standby会尝试维护这些表,不过你必须保证应用不允许。
N :表示该表拥有足够的信息,能够支持在逻辑standby的更新,不过仍然建议你为该表创建一个主键或者唯一索引/约束以提高log应用效率。
假设在某张表中你可以确认数据是唯一的,但是基于效率方面的考虑,不想为其创建主键或唯一约束,怎么办呢?没关系,Oracle早想到了这一点,你可以创建一个DISABLE的Primary-Key Rely约束。
Add a disabled primary-key RELY constraint.(摘自君三思)
维护逻辑standby与primary的数据库同步是通过sql应用实现,SQL应用转换的SQL语句在执行时,对于insert还好说,对于update,delete操作则必须能够唯一定位到数据库待更新的那条记录。如果primary库中表设置不当,可能就无法确认唯一条件。所以,Oracle 建议为表创建一个主键或非空的唯一索引/约束,以尽可能确保sql应用能够有效应用redo数据,更新逻辑standby数据库。
如果能够确认表中的行是唯一的,那么可以为该表创建rely的主键,RELY约束并不会造成系统维护主键的开销,主你对一个表创建了rely约束,系统则会假定该表中的行是唯一,这样能够提供sql应用时的性能。但是需要注意,由于rely的主键约束只是假定唯一,如果实际并不唯一的话,有可能会造成错误的更新哟。
创建rely的主键约束非常简单,只要在标准的创建语句后加上RELY DISABLE即可,例如:
SQL> ALTER TABLE mytab ADD PRIMARY KEY (id, name) RELY DISABLE;
注 意:创建了Rely约束后,Oracle会假定该列是唯一的(给DBA足够的信任),不过并不会对该列的值进行唯一性的验证,因此该列是否唯一只能由DBA来主动维护。
1.1.1 Create a Physical Standby Database
参详物理standby创建
1.1.2 Stop Redo Apply on the Physical Standby Database
Physical备库切换到logical备库,需要在primary库构建LogMiner字典及开启supplemental日志,在这之前应先停用physical备库的MRP进程,以避免提前应用含LogMiner字典的REDO数据,造成转换为逻辑Standby后,SQL应用时没有LogMiner字典数据的REDO数据而影响到逻辑Standby与Primary的正常同步。
SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL;
备库恢复传输redo:
SQL> recover managed standby database disconnect from session;
1.1.3 Prepare the Primary Database to Support a Logical Standby Database
一是将主库LOG_ARCHIVE_DEST_1参数中的VALID_FOR属性改为仅仅联机重做日志有效,而不包括备用重做日志。当primary为主库时,用于存放primary产生的arch,当primary被切换为备库角色后,用于存放自身作为备库产生的归档。
LOG_ARCHIVE_DEST_1='LOCATION=USE_DB_RECOVERY_FILE_DEST VALID_FOR=(ONLINE_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=primary'
二是专门为备用重做日志添加一个新的归档路径LOG_ARCHIVE_DEST_3,也就是说联机日志与备用日志分开,仅当primary库转为备库时有效,当primary库为备库角色时,用于存放从primary库接收到的STANDBY_LOGFILES。
LOG_ARCHIVE_DEST_3='LOCATION=USE_DB_RECOVERY_FILE_DEST VALID_FOR=(STANDBY_LOGFILES,STANDBY_ROLE) DB_UNIQUE_NAME=primary' LOG_ARCHIVE_DEST_STATE_3=ENABLE
- 生成LogMiner字典
生成LogMiner字典,这样redo日志中的变化才能被LogMiner字典的SQL Apply组件正确解析。
SQL> EXECUTE DBMS_LOGSTDBY.BUILD;
另外主键和唯一约束/索引列的supplemental日志是自动生成的,The supplemental logging information ensures each update contains enough information to logically identify each row that is modified by the statement.对于11.2以上的版本,supplemental日志会随primary库传至physical备库,而这之前的版本需要检查primary库与physical 备库是否生成supplemental日志,如果没有则主库通过如下语句生成,然后再执行switchover 或 failover传至physical 备库。
SQL> ALTER DATABASE ADD SUPPLEMENTAL LOG DATA (PRIMARY KEY, UNIQUE INDEX) COLUMNS;
1.1.4 Transition to a Logical Standby Database
- physical备库转logical备库
若physical备库为RAC模式,则需先进行:
SQL> ALTER SYSTEM SET CLUSTER_DATABASE=FALSE SCOPE=SPFILE; SQL> SHUTDOWN ABORT; SQL> STARTUP MOUNT EXCLUSIVE;
转physical备库为logical备库:
SQL> ALTER DATABASE RECOVER TO LOGICAL STANDBY db_name;
- 备库参数配置
SQL> SHUTDOWN; SQL> STARTUP MOUNT; LOG_ARCHIVE_DEST_1='LOCATION=USE_DB_RECOVERY_FILE_DEST VALID_FOR=(ALL_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=standby'
与physical备库所不同的是,logical备库被open后会产生自己的重做日志(redo),因此我们需要配置参数LOG_ARCHIVE_DEST_n。对于逻辑备库,此时存在三种日志文件,即online redo log,archived redo log,standby redolog。
LOG_ARCHIVE_DEST_3='LOCATION=USE_DB_RECOVERY_FILE_DEST VALID_FOR=(STANDBY_LOGFILES,STANDBY_ROLE) DB_UNIQUE_NAME=standby'; LOG_ARCHIVE_DEST_STATE_3=ENABLE
1.1.5 Open the Logical Standby Database
- 由于逻辑standby与primary数据库事务并不一致,因此第一次打开时必须指定resetlogs子句
SQL> ALTER DATABASE OPEN RESETLOGS;
- 应用redo数据
SQL> ALTER DATABASE START LOGICAL STANDBY APPLY IMMEDIATE;
- 查询数据库状态
SQL> select name,open_mode,database_role,protection_mode from v$database;
1.2 Verify the Logical Standby Database Is Performing Properly Standby
Primary库NN用户T1表插入数据
Logical standby库查询
至此,ORACLE 11G 之DATAGUARD搭建逻辑standby成功!
-----------------------------------------------------------------------------------------------------------------------------------------------
dataguard 逻辑备库支持的数据类型及ddl
逻辑备库,数据类型的考虑
1逻辑支持的数据类型
2逻辑备库不支持的数据类型
1逻辑备库支持下面的数据类型
BINARY_DOUBLE
BINARY_FLOAT
BLOB
CHAR
CLOB and NCLOB
DATE
INTERVAL YEAR TO MONTH
INTERVAL DAY TO SECOND
LONG
LONG RAW
NCHAR
NUMBER
NVARCHAR2
RAW
TIMESTAMP
TIMESTAMP WITH LOCAL TIMEZONE
TIMESTAMP WITH TIMEZONE
VARCHAR2 and VARCHARsql apply 支持下面的数据类型,要求主库上设置兼容
multibyte clob支持(要求主库的compatibility是10.1或更高)
没有LOB与overflows的iot支持(要求主库compatibilty10.1或更高)
带LOB与overflows的iot,要求主库compatibility 10.2或更高)
逻辑备库不支持下面的数据类型
BFILE
Collections (including VARRAYS and nested tables)
Encrypted columns
Multimedia data types (including Spatial, Image, and Context)
ROWID, UROWID
User-defined types
XMLType
存储类型的考虑
逻辑备库支持下面的存储类型
Cluster tables (including index clusters and heap clusters)
Index-organized tables (partitioned and nonpartitioned, including overflow segments)
Heap-organized tables (partitioned and nonpartitioned逻辑备库不支持的存储类型
不支持段压缩存储类型
pl/sql包的考虑
支持的pl/sql包
oracle pl/sql不修改系统元数据但是也许会修改用户数据是被sql apply支持的。如:DBMS_LOB, DBMS_SQL, and DBMS_TRANSACTION
不支持的pl/sql包
修改系统元数据的包是不被支持的。如:are DBMS_JAVA, DBMS_REGISTRY, DBMS_ALERT, DBMS_SPACE_ADMIN, DBMS_REFRESH, DBMS_REDEFINITION, DBMS_SCHEDULER, and DBMS_AQ.
dbms_job是支持的,被复制到备库的job不会运行,当发生角色切换的时候,job会继续运行。
不支持的表,序列,和视图
一些schema会被sql apply跳过,为了看哪些schema会被跳过,查看下面的视图
SELECT OWNER FROM DBA_LOGSTDBY_SKIP WHERE STATEMENT_OPT = 'INTERNAL SCHEMA';
为了看主库包含哪些不被支持的对象,查看下面的视图
SELECT DISTINCT OWNER,TABLE_NAME FROM DBA_LOGSTDBY_UNSUPPORTED ORDER BY OWNER,TABLE_NAME;
为了查看列和列的类型,使用下面的语句
SELECT COLUMN_NAME,DATA_TYPE FROM DBA_LOGSTDBY_UNSUPPORTED WHERE OWNER='OE' AND TABLE_NAME = 'CUSTOMERS';
被逻辑备库跳过的sql
ALTER DATABASE
ALTER MATERIALIZED VIEW
ALTER MATERIALIZED VIEW LOG
ALTER SESSION
ALTER SYSTEM
CREATE CONTROL FILE
CREATE DATABASE
CREATE DATABASE LINK
CREATE PFILE FROM SPFILE
CREATE MATERIALIZED VIEW
CREATE MATERIALIZED VIEW LOG
CREATE SCHEMA AUTHORIZATION
CREATE SPFILE FROM PFILE
DROP DATABASE LINK
DROP MATERIALIZED VIEW
DROP MATERIALIZED VIEW LOG
EXPLAIN
LOCK TABLE
SET CONSTRAINTS
SET ROLE
SET TRANSACTION
应用dml的考虑
在主库上的直接路径insert到逻辑备库上会变成常规的insert
并行dml事务在逻辑库上不并行执行
在主库上的批量更新或删除(一个命令导致多行被修改),在备库上的应用就像是单行被修改,因此表上有唯一键或是主键是很必要的。
应用ddl的考虑
并行ddl在备库上不并行
ddl事务在备库上顺序执行
CREATE TABLE AS SELECT
(CTAS) statements are executed such that the DML activities (that are part of the CTAS statement) are suppressed on the logical standby database. The rows inserted in the newly created table as part of the CTAS statement are mined from the redo log files and applied to the logical standby database usingINSERT
statements.--------------------------------------------------------------------------------------------------------------------------------------------------------
ORACLE逻辑备库过滤DDL语句测试
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。2010年因为需要评估DATAGUARD 和 GOLDENGATE某些功能,搭建了环境做了一些功能比较测试本次测试是过滤DROP PARTITION 语句,源库进行DROP 历史PARTITION 但是目标库保留历史PARTITION最后是使用了GOLDENGATE,到目前为止一直在使用
1.环境介绍
DATABASE HOSTNAME IP DB_UNIQUE_NAME
主 DG1 192.168.128.2 DG1
备 DG2 192.168.128.3 DG2
2.测试表准备
在主库DG1用户TT下创建分区表TCTAUDLG
CREATE TABLE TT.TCTAUDLG(
AC_DATE NUMBER(8) default 0 not null,
JRN_NO NUMBER(11) default 0 not null,
IN_TIM CHAR(17) default ' ' not null,
OUT_TIM CHAR(17) default ' ' not null,
TR_STS CHAR(1) default ' ' not null,
MSG_CODE CHAR(6) default ' ' not null
)
PARTITION BY RANGE (ac_date)
(PARTITION TCTAUDLG_20091122 VALUES LESS THAN (20091122) TABLESPACE USERS,
PARTITION TCTAUDLG_20091130 VALUES LESS THAN (20091130) TABLESPACE USERS,
PARTITION TCTAUDLG_20091207 VALUES LESS THAN (20091207) TABLESPACE USERS,
PARTITION TCTAUDLG_20091215 VALUES LESS THAN (20091215) TABLESPACE USERS
);
Insert into TT.TCTAUDLG
(AC_DATE, JRN_NO, IN_TIM, OUT_TIM, TR_STS,
MSG_CODE)
Values
(20091121, 0, ' ', 'PARTITION1122 ', ' ',
' ');
Insert into TT.TCTAUDLG
(AC_DATE, JRN_NO, IN_TIM, OUT_TIM, TR_STS,
MSG_CODE)
Values
(20091124, 0, ' ', 'PARTITION1130 ', ' ',
' ');
Insert into TT.TCTAUDLG
(AC_DATE, JRN_NO, IN_TIM, OUT_TIM, TR_STS,
MSG_CODE)
Values
(20091206, 0, ' ', 'PARTITION1207 ', ' ',
' ');
COMMIT;
为了测试简便,每个分区插入一条记录,DROP掉一个分区便少一条记录。
3.验证备库DG2中此表结构与数据全部同步过来
SQL> desc TT.TCTAUDLG
Name Null? Type
----------------------------------------- -------- ----------------------------
AC_DATE NOT NULL NUMBER(8)
JRN_NO NOT NULL NUMBER(11)
IN_TIM NOT NULL CHAR(17)
OUT_TIM NOT NULL CHAR(17)
TR_STS NOT NULL CHAR(1)
MSG_CODE NOT NULL CHAR(6)
SQL> SELECT * FROM TT.TCTAUDLG;
AC_DATE JRN_NO IN_TIM OUT_TIM T MSG_CO
---------- ---------- ----------------- ----------------- - ------
20091121 0 PARTITION1122
20091124 0 PARTITION1130
20091206 0 PARTITION1207
以上返回结果与主库DG1 的完全一致。
4.停止备库DG2 APPLY进程(这一步必不可少,而且与下一步的顺序不能交换)
SQL> ALTER DATABASE STOP LOGICAL STANDBY APPLY ;
5.在备库DG2上创建SKIP DDL语句的规则
execute dbms_logstdby.skip (stmt => 'SCHEMA_DDL',schema_name => 'TT', object_name => 'TCTAUDLG', proc_name => null);
6.在备库上验证此规则是否添加成功
SQL> select * from dba_logstdby_skip where owner like '%TT%';
ERROR STATEMENT_OPT OWNER NAME U E PROC
--------- -------------------- ---------- ---------- - - -----
N SCHEMA_DDL TT TCTAUDLG Y
7.重新开启备库DG2 的APPLY进程
SQL> ALTER DATABASE START LOGICAL STANDBY APPLY IMMEDIATE;
8.在主库DG1 演示删除掉一个历史分区
SQL> ALTER TABLE TT.TCTAUDLG DROP partition TCTAUDLG_20091122;
查询主库数据, TCTAUDLG_20091122已经被删除
SQL> SELECT * FROM TT.TCTAUDLG;
AC_DATE JRN_NO IN_TIM OUT_TIM T MSG_CO
---------- ---------- ----------------- ----------------- - ------
20091124 0 PARTITION1130
20091206 0 PARTITION1207
9.查看备库DG2 TCTAUDLG_20091122是否还存在,结果是应该存在才正确
SQL> SELECT * FROM TT.TCTAUDLG;
AC_DATE JRN_NO IN_TIM OUT_TIM T MSG_CO
---------- ---------- ----------------- ----------------- - ------
20091121 0 PARTITION1122
20091124 0 PARTITION1130
20091206 0 PARTITION1207
查看备库DG2 ALERT LOG记录信息如下
LOGSTDBY status: ORA-16205: DDL skipped due to skip setting 此DDL 语句已经被APPLY 进程跳过。
结论:从功能上来说,ORACLE逻辑数据库可以做到在删除主库表的历史分区同时保留逻辑库上此表的历史分区。