学习Advanced Replication(高级复制) -zt

一、 概述
1. Replication 使用分布式数据库技术在多个站点之间共享数据。
2. Replicated Database 和Distributed Database 并不一样,在分布式数据库系统中数据在多个站点同时有效,但是一个表只会存在于一个站点中,而对于Replication 来说相同的数据将同时存在于多个站点中。

3. 使用replication 的原因:
1) Availability:也就是提供了优秀的failover 保护
2) Performance:由于有多个server,所以可以将用户业务分布在不同的server 上
3) Disconnected computing:实体化视图允许用户在和master 断开后使用数据库
的子集,在重新连接上master 之后再进行两者的同步。
4) Network load reduction:由于有多个server,所以可以减少master 的网络请

5) Mass deployment:通过变量产生自定义的实体化视图以满足多种需求
4. 在不同的Oracle 发行版本之间以及不同操作系统的Oracle 之间都可以使用Advanced
Replication。
5. Replication 中的几个概念:
1) replication object:复制对象,指需要作复制的对象(object),包括表,索引,
存储过程等等。复制对象的更新遵循事务一致性规则(transactionally consistent
manner)。
2) replication groups:复制组,是复制对象(replication object)的集合称为group,
oracle 以replication group 的形式来管理复制。一个组可以包含多个模式的object,
一个模式也可以有多个组中的object,但是每个replication object 都只能属于一个
replication group。
3) replication sites:复制站点,包含两种类型,主体站点(master sites)和实
体化视图站点(materialized view sites)。一个site 可以担任一个replication
group 中的mater site 同时又担任另外一个replication group 中的materialized
view site,注意必须是另外一个组,而不能是同一个replication group。
4) scheduled links:一个数据库链接(database link),包含一个由用户定义的计划,
来将需要更新的事务推到其它的master sites,当创建scheduled link 的时候,oracle
将在本地任务队列中创建一个任务。
5) master definition site:主体定义站点,大部分的高级复制配置都需要在一个站
点上作,这个站点就是maserdef site。
6. Replication 环境的几种类型
1) Multimaster Replication
2) Materialized View Replication(也可以称为是Single Master Replication)
3) Multimaster and Materialized View Hybrid Configurations
Multimaster Replication 和Materialized View Replication 的区别在于:
前者必须是全表复制而后者可以是master 表的一部分
前者允许在每一个transaction 之后都进行复制,而后者是属于批处理复制
两者都使用scheduled links 进行数据同步操作。
Materialized View Replication 中的materialized view 可能有以下几种类型:
1) Read-Only Materialized Views:只读的实体化视图
2) Updatable Materialized Views:允许更新,同时允许将更新复制到master site
3) Writeable Materialized Views:允许更新,但是每次refresh 的时候,更新都会丢

7. 介绍Multimaster Replication 中的复制方式
1) Asynchronous replication
在一个master 上发生的变化将在推后的时间内更新到其他的master 上
2) Synchronous replication
在一个master 上发生的变化将立刻更新到其他的master 上
3) Procedural replication
必须给每个site 上的包都生成一个wrapper,所有的数据变化应该通过包中的存储
过程完成,当某个master 上的procedure 被调用,wapper 将保证其他site 中的存
储过程也被调用(同步或者不同步)。将大量的数据操作放到一个procedure 中,
然后对于procedure 的调用将被同步,用处在于在于有大数据量操作的时候可以减
少网络负载。
二、 MR 的概念和构架
MR 是Master Replication,也就是主体站点复制的概念,是高级复制区别于普通复制的一个
重要的功能。本章节对于MR 中出现的种种概念作详细解释。
MR 分为single master 和multi master 两种。single master 指一个master site 支持多个
materialized view site,而multi master 则包含多个master site。
Multimaster Replication 也被称为peer-to-peer 或者n-way replication,任何一个master
上发生的变化都将被送到其它的master 上。
1. 为什么使用Multimaster Replication。
Failover:当主数据库发生问题的时候,可以通过配置Oracle Net 来实现automatic
connect-time failover,需要将客户端的tnsnames.ora 中的FAILOVER_MODE 参数设置
为ON。同时在主数据库正常的时候,其它的master site 仍然可以作为一个具有完全功
能的数据库来支持其它业务,比如报表等。
Load Balancing::提供读动态平衡以及更本地化的数据存取。
2. 比较RAC(Oracle Real Application Clusters)和Advanced Replication
Load Balancing::高级复制提供读动态平衡,而RAC 则提供读写动态平衡。因为每一
次写操作都会在所有的replication site 上体现,所以高级复制不能提供写动态平衡。
Survivability::高级复制提供更加强有力的灾难恢复功能,因为高级复制环境中的各
个site 可以位于物理上的不同地点,而RAC 因为使用的是磁盘阵列或其他类型的并行系统,
所以通常在同一个物理地点。
Interoperability:高级复制可以在不同平台和操作系统的Oracle 之间实现,而RAC
环境则必须运行在相同的平台上。
3. Multimaster Replication Process
Asynchronous Replication:
说明:使用非同步复制能够减少网络资源和硬件资源的消耗,但是不同的master sites 之间
会有一段时间不同步,并且可能会造成数据冲突。
以下描述非同步复制的过程:
1) 用户执行DML 操作或者执行replicated procedure 的wrapper,当一个table 被设
定为需要复制,那么对于此表的任何DML 操作都会被捕获并且复制到其他的
master site。对于每一行被插入,更新或者删除的数据都将由一个内部触发器来创
建一个deferred remote procedure call (RPC)并且放在deferred transaction queue
中,如果一个存储过程被设置为需要复制并且它的wrapper 被执行,则这个
procedure call 被放置在transaction queue 中。由于内部触发器是由Oracle 本身
内部维护的,所以可以以最小的系统资源消耗来很快地获取需要复制的对象的变
化。
2) deferred transaction queue 中保存着所有的deferred RPCs。每个site 都有一个事
务队列,这个队列可以被多个replication group 共用。
3) 在指定的间隔之后或者被手工调用,事务将被传递到其他的site,每个site 都可能
有不同的间隔。
4) 事务在这些site 上被应用,如果出错该事务将被放置到一个错误队列中,以备DBA
检查处理,如果出现数据冲突,冲突解决方法将被调用,如果冲突无法解决那么将
被记录在错误队列中
5) 当事务在所有的remote master sites 上被成功执行之后,并不会从源site 的事务
队列中立刻删除,删除工作将由另外的purge job 来执行,此job 的执行间隔可以
由用户来定义。
Synchronous Replication:
说明:同步复制始终在同一个transaction 中完成,如果整个环境中的任何一个site 没有成
功执行事务,那么整个transaction 将被回滚,包括源site。这就保证了数据一致性。
以下描述同步复制的过程:
1) 用户执行DML 操作或者执行replicated procedure 的wrapper,操作被内部触发器
立刻捕获。
2) 事务被传递到其他site 并且立刻执行,任何一个site 出错,就回滚整个事务。
4. 冲突解决方案的概念
冲突的类型:更新冲突,唯一性冲突,删除冲突。
当发生冲突的时候,冲突解决方法将被调用以解决冲突,如果无法解决,则被记录到目
标站点的错误队列中。记录到错误队列中的冲突只能由数据库管理员手动解决。
为了实现冲突解决方案,可能会需要修改表结构,比如如果使用最新时间戳的解决方案,
那么就应该在表中添加一个timestamp 列。
5. 配置高级复制的工具
1) 图形界面:Oracle Enterprise Manager 提供了一个友好的GUI 界面用以配置高级复
制。
2) 命令行方式:Oracle 提供了一套replication management application programming
interface (API)来支持用户编写自定义的脚本用以配置高级复制,这些API 是一系
列的PL/SQL packages。实际上GUI 界面的高级配置工具也是调用这些API 来完成
配置的。
注意点:
在高级复制环境中的对于需要复制的对象作任何DDL 操作,都应该使用高级复制配置
工具来作,比如利用DBMS_REPCAT 包中的相应存储过程。在有些场合下也可以用导出
导入(EXP/IMP)来创建复制对象。在SQL*PLUS 中直接执行的任何DDL 操作都不会被
复制到其它的site 上。
6. 高级复制中的几个角色
Replication Administrator:默认名称是repadmin,也可以修改。
Propagator:一个高级复制环境中可能有多个RA 来管理不同的schema,但是只能有
一个propagator 将延迟处理事务队列中的事务传递到目标站点。
Receiver :负责接收和处理从propagator 处传来的延迟处理事务。可以通过
DBMS_REPCAT_ADMIN 包中REGISTER_USER_REPGROUP 存储过程来注册一个receiver。
7. Database Links
数据库链接在高级复制环境中提供了数据传送的通道,在一个MMR 环境中,如果有N
个Master Site,就会有N-1 个数据库链接。在MVR 环境中,则只需要从实体化视图站
点上到主站点的数据库链接。如果使用设置向导来创建dblink,则会在USING 后面使用
连接描述字串,而不是连接服务名,这样在对方数据库发生变化的时候,就必须删除重
建现有的dblink,所以我们应该手动设定dnlink,从而在USING 后面使用连接服务名。
这样即使对方数据库改变,我们也只需要修改tnsnames.ora 中的配置即可,而不需要
重建dblink。
8. 可以进行复制的对象
• Tables
当一个对象被复制到目标站点上时,复制支持不会自动生成。利用这个特点可以快速地
发布一个标准的数据库环境到另外的站点上。
• Indexes
作为约束的索引,当表在主站点上被创建的时候,会自动在复制站点上创建,但是对于
提高性能的索引则不会被自动创建而必须手动指定。对于索引被复制到目标站点之后,
等同于本地的索引,不需要再添加复制支持。
• Packages and Package Bodies
存储过程中的所有参数必须是IN 的,OUT 和INOUT 不被支持。存储过程和函数也必须
定义在包中,单独的存储过程和函数无法进行复制。
• Procedures and Functions
虽然单独的存储过程和函数无法进行复制,但是仍然可以在高级复制环境中利用复制来
将单独的存储过程和函数发布到远程的站点上,就像在远程站点本地创建的一样。
• User-Defined Types and Type Bodies
所有的用户定义类型在所有的复制站点上都必须存在而且必须完全相同。
• Triggers
一个比较重要的应用就是在DML 操作的时候在表的timestmap 列中插入当前的系统时
间。为了防止触发器被重复调用,必须要使用API 来判断DML 操作是在本地发起的还
是通过高级复制传递过来的。如下例:
CREATE OR REPLACE TRIGGER hr.insert_time
BEFORE
INSERT OR UPDATE ON hr.employees FOR EACH ROW
BEGIN
IF DBMS_REPUTIL.FROM_REMOTE = FALSE THEN
:NEW.TIMESTAMP := SYSDATE;
END IF;
END;
• Views, Object Views, and Synonyms
只是简单地复制到其它站点,不会产生任何内部触发器或者包来监控这些被复制的对象
的改变。由于是复制对象,所以仍然可以使用高级复制工具或者API 来进行修改和删除。
• Indextypes
必须手工指定复制。可以用高级复制工具或者CREATE_MASTER_REPOBJECT 存储过程。
• User-Defined Operators
复制情况跟视图,同义词等相同,只是简单的复制而已。
注意:高级复制不支持sequence。如果想实现高级复制环境中的序列唯一性,可以有
以下几种方法:
1. 使用SELECT SYS_GUID() OID FROM DUAL;这样将会产生全球唯一的GUID
2. 在序列前面添加站点名称,比如唯一的GLOBAL_NAME
3. 在各个复制站点规划不会重复的序列,比如站点A 的序列从1 开始,以10 递增,
站点B 的序列从3 开始,以10 递增。
9. 高级复制环境中的队列
Oracle 利用Internal Triggers 来捕获对象变化,并且生成RPCs(remote procedure calls),
RPCs 中包含目标站点上的internal procedure 的执行命令以及需要复制的数据,RPCs
存储在deferred transaction queue 中,当一个RPC 到达目标站点,该站点上相应的
internal procedure 将被运行以应用RPC 来完成复制操作。
高级复制环境中的队列包含Deferred Transaction Queue,Error Queue 和Job Queue。
Job Queue 中包含的作业有三种:将延迟事务推到远程主站点的作业,将已经应用过的
事务从延迟事务处理队列中删除的作业,刷新实体化视图更新组的作业。
10. 管理请求(Administrative Request)- 管理机制
什么是管理请求?
在DBA_REPCATLOG 视图中查看Administrative Requests 的状态。当管理请求在所有的
主站点上成功执行以后,管理请求将从所有的主站点包括主体定义站点中的管理请求队
列中,也就是DBA_REPCATLOG 视图中删除。
DBA_REPCATLOG 视图中管理请求的几种状态:
1) READY:表示请求准备被执行。如果长时间处于该状态,可以手动执行
DBMS_REPCAT.DO_DEFERRED_REPCAT_ADMIN 存储过程来执行请求。
2) AWAIT_CALLBACK:这种状态只会出现在主体定义站点上,表示正在等待
其它的主站点执行请求并且返回结果。
3) ERROR:表示请求执行错误
4) DO_CALLBACK:这种状态只会出现在非主体定义站点上,表示要通知主体
定义站点请求执行的结果。
11. 主体组(Master Group)- 组织机制
在高级复制环境中,Oracle 用复制组来管理复制对象。而在多主体复制(multimaster
replication)环境中复制组就被称为主体组(Master Group)。在不同的复制站点上的相
应主体组中必须包含相同的复制对象。
12. Column Groups - 组织机制
Column Group 是在冲突解决方案中扮演角色的多个字段的集合。如果组中的某个字段
引发了冲突,那么其余的字段可以用来作解决这个冲突。打个比方,如果一个表的column
group 中包含price 和timestamp 字段,那么当启用时间戳冲突解决方案(timestamp
conflict resolution routine)时,timestamp 字段就可以用来解决price 字段中发生的冲
突。
可能刚开始的时候会想把表中的所有字段都放入一个Column Group 中,这样确实使配
置和管理都更简单了些,但是却会降低复制的性能并且可能会引发潜在的数据冲突。在
后面的性能机制部分,大家将会看到如果一个column group 中发生了冲突,那么oracle
的最小化通信功能(minimum communication feature)将不会从其它的column group
中传递来数据。所以将所有的字段全部放入一个column group 将减弱最小化通信功能
带来的好处, 除非使用了DBMS_REPCAT 包中的SEND_OLD_VALUES 和
COMPARE_OLD_VALUES 存储过程。在后面的冲突解决方案的概念和体系结构章节中将
会有更详细的描述。
13. 传播类型 - 传播机制
异步数据复制通常也被称为:store-and-forward data replication
同步数据复制通常也被称为:real-time data replication
由于同步复制采取的锁机制,所以当同时更新同一行数据时,会产生死锁的现象。当同
步更新一个复制表时,Oracle 首先锁住本地行,然后使用一个AFTER ROW 触发器来锁
住远端的行。当事务在所有的站点都提交之后,Oracle 才会解锁。同步数据复制极为依
赖系统和网络的可用性,因为只要当复制环境中的所有站点都可用时,事务才能正常进
行。
混合模式的数据复制:
1) 假设创建了A 是masterdef site,然后添加了B 为同步数据复制,再添加C 为
非同步复制,那么此时AB 之间是同步,AC 和BC 之间都是非同步。
2) 假设创建了A 是masterdef site,然后添加了C 为非同步数据复制,再添加B
为同步复制,那么此时AB 和BC 之间是同步,AC 之间是非同步。
14. Initiating 方法 - 展开机制
当使用同步复制的时候,DML 传播被立刻处理并且被自动展开。
如果是使用异步复制,那么可以用下面的方法传播延迟事务:
计划作业:大部分场合,都是利用计划作业在指定的时间间隔后自动传播延迟事务。
手动传播:如果不想等待计划作业的自动传播,也可以利用存储过程或者复制管理工具
来手动传播改动。
15. 并行传播(Parallel Propagation) - 性能机制
16. 最小化通信(Minimum Communication) - 性能机制
17. 延迟秒数(Delay Seconds) - 性能机制
上面三个参数(15,16,17 值得好好研究并且进行调整,以后会补齐这部分内容)
18. 复制保护机制:
在多主体复制环境中,Oracle 将保证就算发生错误的时候,事务传播也不会丢失,同样
同一个事务也不可能传播两次。
正确的传播并不以为着延迟事务在远程站点就正确执行了,可能因为无法解决的冲突或
者说远程站点磁盘空间不足等原因延迟事务执行失败,那么这样的错误将会记录在远程
站点的错误队列中。
19. 数据传播的依赖性维护
非并行传播中,Oracle 按照本地站点的事务commit 顺序来在远程站点应用事务。而并
行传播中,Oracle 则会记录最新事务产生的SCN,如果存在事务之间的依赖性,那么
Oracle 将先在远程站点应用比这个SCN 小或者等于这个SCN 的事务,然后再应用这个
最新的事务,这是一个非并行的应用,只有当不存在事务依赖性的时候,才会真正利用
并行来应用延迟事务。
记录SCN 有两种方式,一种是数据块级别的,一种是行级别的。
当创建表的时候,如果使用了:
NOROWDEPENDENCIES,这是默认属性,那么Oracle 将会以数据块级别方式来记录
SCN。这样存储在同一个数据块中的多行记录都只会有一个最新的SCN,旧的会被新生
成的覆盖。
ROWDEPENDENCIES,那么将对表中的每一行都记录SCN。在同一个数据块中的多
行记录将分别保留自己的SCN,这样每一行记录都需要额外的6 个字节的存储空间。但
是这将提高并行传播时应用延迟事务的效率。(使用这个特性,要求数据库的初始化参
数中COMPATIBLE=9.0.1 或者更高)。可以使用以下SQL 来检查那些表启用了这个特性:
SQL> SELECT OWNER, TABLE_NAME FROM DBA_TABLES
WHERE DEPENDENCIES = 'ENABLED';
如果没有使用ROWDEPENDENCIES,那么我们可以设法让事务依赖性最小,这样来达
到提高复制环境应用效率的目的。比如我们可以创建多个freelist,这样可以在大量insert
的时候将不同事务更新的数据放置到不同的数据块中。
另外在程序设计的时候,我们也应该尽量避免大量的事务同时更新同一张小表的现象出
现,比如说有些应用会设计一张小表来模拟序列(Sequence),用以生成唯一的主键。
这样就会迫使多个事务同时更新同一个数据块。对于这种情况,我们应该改为使用
Sequence 并且缓存Sequence 的生成。
20. 冲突解决机制
为了正确地侦测复制冲突,Oracle 必须能够找到在不同的站点之间对于相关行的唯一标示。
这就要求在复制环境中,每个表都必须有主键,如果没有主键,那么也必须指定多个字段的
组合来作为唯一标示。
Oracle 自己提供了以下几种冲突解决方案:
1) Latest and Earliest Timestamp
2) Overwrite and Discard
3) Maximum and Minimum
4) Additive and Average
5) Timestamp
6) Priority Group
7) Site Priority
如果上述Oracle 提供的解决方案无法满足应用的需求,那么也可以利用PL/SQL 来编写自定
义的冲突解决方案。
下面章节我们将进一步研究冲突解决方案。
三、 冲突解决方案的概念和构架
基本上我们在设计系统的时候,应该尽量避免产生冲突,但是如果必须允许在多个主体站点
同时对复制对象的更改,那么我们就一定要考虑冲突解决方案。
对于普通的插入(主键冲突),更新,删除产生的冲突很容易理解,但是还有一些其它的情
况也会产生冲突,比如在3 个或者3 个以上的复制主站点环境中,可能会产生下面例子中
的这种Ordering Conflicts,其实也是更新冲突的一个例子。
这个复制环境中有A,B,C 三个主站点,每个站点都设置了优先级,A 是30,B 是25,C 是
10,而x 则是被分配了site-priority 冲突解决方案的column group 中的一列。
Time Action
Site
A
Site
B
Site
C
1 所有的主体站点上 x = 2. 2 2 2
2 站点A 更新 x = 5. 5 2 2
3 站点C 由于故障宕机了,或者网络出现故障. 5 2 down
4 站点A 将更新推到站点B.
站点A 和站点B 上 x = 5.
站点C 仍然不可用.
这个更新事务仍然保留在站点A 的队列中.
5 5 down
5 站点C 修复了,此时站点C 上 x = 2.
而站点A 和站点B 上 x = 5.
5 5 2
6 站点B 将x = 5 更新为 x = 7. 5 7 2
7 站点B 将更新推到站点A.
站点A 和站点B 上 x = 7.
站点C 上 x = 2.
7 7 2
8 站点B 将更新推到站点C.
站点C 认为旧值x = 2;
站点B 推过去的旧值 x = 5.
Oracle 检测到冲突,然后应用站点B 上的更新来解决冲突。因
为站点B 上设置了优先级25 比站点C 上设置的优先级10 要高.
所有站点上 x = 7.
7 7 7
9 站点A 将延迟事务 (x = 5) 推到站点C.
Oracle 检测到冲突,因为站点C 上的当前值(x = 7) 和站点A
上的旧值(x = 2)不符合.
站点A 比站点C 有更高的优先级(30).
Oracle 用这个过时的更新解决冲突,这样站点C 上的x = 5.
Time Action
Site
A
Site
B
Site
C
因为这样的ordering conflict, 整个复制环境就不再一致了.
四、 冲突解决机制的研究
实际上Oracle 的dbms_rectifier_diff.DIFFERENCES 过程,内部操作就是执行连个minus 操
作把两边的差异记录下来,作为冲突解决的数据。
这部分后台操作可以通过跟踪Oracle 进程得到:
SQL> alter session set events '10046 trace name context forever,level 12';
Session altered.
Elapsed: 00:00:00.02
SQL> begin dbms_rectifier_diff.DIFFERENCES(
2 SNAME1 =>'HAWA',
3 ONAME1 =>'TEST',
4 REFERENCE_SITE =>'AVATAR.COOLYOUNG.COM.CN',
4 SNAME2 =>'HAWA',
6 ONAME2 =>'TEST',
7 COMPARISON_SITE =>'AUTHAA.COOLYOUNG.COM.CN',
8 WHERE_CLAUSE =>NULL,
9 COLUMN_LIST =>NULL,
10 MISSING_ROWS_SNAME =>'HAWA',
11 MISSING_ROWS_ONAME1 =>'MISSING_ROWS_TEST',
12 MISSING_ROWS_ONAME2 =>'MISSING_LOCATION_TEST',
13 MISSING_ROWS_SITE =>'AVATAR.COOLYOUNG.COM.CN',
14 MAX_MISSING =>500,
15 COMMIT_ROWS =>100
16 );
17 end;
18 /
PL/SQL procedure successfully completed.
Elapsed: 00:00:01.97
SQL> alter session set events '10046 trace name context off';
从跟踪文件中我们可以清晰的看到(注意你所定义的所有参数在此都会有所体现):
1.首先是一个正向Minus
DECLARE
row_count BINARY_INTEGER := 0;
missing_rows BINARY_INTEGER := 0;
arowid ROWID;
CURSOR c
IS
SELECT "DATLOGONTIME", "NUMGENDER", "NUMSTATUS", "NUMUSERID", "VC2IP",
"VC2USERNAME"
FROM "HAWA"."TEST"
MINUS
SELECT "DATLOGONTIME", "NUMGENDER", "NUMSTATUS", "NUMUSERID", "VC2IP",
"VC2USERNAME"
FROM "HAWA"."TEST"@authaa.coolyoung.com.cn;
BEGIN
FOR r IN c
LOOP
missing_rows := missing_rows + 1;
IF missing_rows > 500
THEN
COMMIT;
EXIT;
END IF;
INSERT INTO "HAWA"."MISSING_ROWS_TEST"
("DATLOGONTIME", "NUMGENDER", "NUMSTATUS",
"NUMUSERID", "VC2IP", "VC2USERNAME"
)
VALUES (r."DATLOGONTIME", r."NUMGENDER", r."NUMSTATUS",
r."NUMUSERID", r."VC2IP", r."VC2USERNAME"
);
SELECT ROWID
INTO arowid
FROM "HAWA"."MISSING_ROWS_TEST"
WHERE ( datlogontime = r."DATLOGONTIME"
OR (datlogontime IS NULL AND r."DATLOGONTIME" IS NULL)
)
AND ( numgender = r."NUMGENDER"
OR (numgender IS NULL AND r."NUMGENDER" IS NULL)
)
AND ( numstatus = r."NUMSTATUS"
OR (numstatus IS NULL AND r."NUMSTATUS" IS NULL)
)
AND (numuserid = r."NUMUSERID")
AND (vc2ip = r."VC2IP" OR (vc2ip IS NULL AND r."VC2IP" IS NULL))
AND ( vc2username = r."VC2USERNAME"
OR (vc2username IS NULL AND r."VC2USERNAME" IS NULL)
);
INSERT INTO "HAWA"."MISSING_LOCATION_TEST"
(present, absent, r_id
)
VALUES ('AVATAR.COOLYOUNG.COM.CN', 'AUTHAA.COOLYOUNG.COM.CN',
arowid
);
row_count := row_count + 1;
IF row_count >= 100
THEN
COMMIT;
row_count := 0;
END IF;
END LOOP;
COMMIT;
END;
2.其次是一个反向Minus
DECLARE
row_count BINARY_INTEGER := 0;
missing_rows BINARY_INTEGER := 0;
arowid ROWID;
CURSOR c
IS
SELECT "DATLOGONTIME", "NUMGENDER", "NUMSTATUS", "NUMUSERID", "VC2IP",
"VC2USERNAME"
FROM "HAWA"."TEST"@authaa.coolyoung.com.cn
MINUS
SELECT "DATLOGONTIME", "NUMGENDER", "NUMSTATUS", "NUMUSERID", "VC2IP",
"VC2USERNAME"
FROM "HAWA"."TEST";
BEGIN
FOR r IN c
LOOP
missing_rows := missing_rows + 1;
IF missing_rows > 500
THEN
COMMIT;
EXIT;
END IF;
INSERT INTO "HAWA"."MISSING_ROWS_TEST"
("DATLOGONTIME", "NUMGENDER", "NUMSTATUS",
"NUMUSERID", "VC2IP", "VC2USERNAME"
)
VALUES (r."DATLOGONTIME", r."NUMGENDER", r."NUMSTATUS",
r."NUMUSERID", r."VC2IP", r."VC2USERNAME"
);
SELECT ROWID
INTO arowid
FROM "HAWA"."MISSING_ROWS_TEST"
WHERE ( datlogontime = r."DATLOGONTIME"
OR (datlogontime IS NULL AND r."DATLOGONTIME" IS NULL)
)
AND ( numgender = r."NUMGENDER"
OR (numgender IS NULL AND r."NUMGENDER" IS NULL)
)
AND ( numstatus = r."NUMSTATUS"
OR (numstatus IS NULL AND r."NUMSTATUS" IS NULL)
)
AND (numuserid = r."NUMUSERID")
AND (vc2ip = r."VC2IP" OR (vc2ip IS NULL AND r."VC2IP" IS NULL))
AND ( vc2username = r."VC2USERNAME"
OR (vc2username IS NULL AND r."VC2USERNAME" IS NULL)
);
INSERT INTO "HAWA"."MISSING_LOCATION_TEST"
(present, absent,
r_id
)
VALUES ('AUTHAA.COOLYOUNG.COM.CN', 'AVATAR.COOLYOUNG.COM.CN',
arowid
);
row_count := row_count + 1;
IF row_count >= 100
THEN
COMMIT;
row_count := 0;
END IF;
END LOOP;
COMMIT;
END;
经过这两个步骤的操作,Oracle 定位了冲突数据。
可是注意,如果在解决这个问题时你没有挂起复制,Oracle 得到的数据可能是存在问题的。
而且,如果你不指定column list,那么两边的数据可能会因为某些特殊字段(如时间字段)的
特殊处理而存在差异。
那么这时候手工介入不可避免。
我们首先先把两个重要参数的用法说明一下。
一个是WHERE_CLAUSE,另外一个是COLUMN_LIST。
WHERE_CLAUSE 用于限定进行差异比较的范围,这可以极大的缩减结果集的数量,使用索
引加快访问速度等。
比如我这里使用NUMGENDER=1,只比较性别为"女"这一部分用户数据。
COLUMN_LIST 用于限定比较字段,如果你能通过某个字段,如主键等确定数据差异,那么
你完全可以只比较单个字段。
而且显然可以轻易通过全索引扫描来完成比较,加快比较速度。
我这里使用NUMUSERID,用户ID 来比较。
但是注意,这样的比较结果中将只包含NUMUSERID 信息,当然我们可以轻易通过
NUMUSERID 和原表的比较补全MISSING_ROWS_TEST 表的信息。
begin dbms_rectifier_diff.DIFFERENCES(
SNAME1 =>'HAWA',
ONAME1 =>'TEST',
REFERENCE_SITE =>'AVATAR.COOLYOUNG.COM.CN',
SNAME2 =>'HAWA',
ONAME2 =>'TEST',
COMPARISON_SITE =>'AUTHAA.COOLYOUNG.COM.CN',
WHERE_CLAUSE =>'NUMGENDER=1',
COLUMN_LIST =>'NUMUSERID',
MISSING_ROWS_SNAME =>'HAWA',
MISSING_ROWS_ONAME1 =>'MISSING_ROWS_TEST',
MISSING_ROWS_ONAME2 =>'MISSING_LOCATION_TEST',
MISSING_ROWS_SITE =>'AVATAR.COOLYOUNG.COM.CN',
MAX_MISSING =>500,
COMMIT_ROWS =>100
);
end;
/
这段代码供参考。
Ok,我们继续前面的讨论。
我们提到,如果存在差异,通常需要手工介入。
清楚了DIFFERENCES 的原理,实际上我们完全可以手工来完成这个过程。
以下是我的手工操作步骤,目的是为了准确性及减轻数据库压力:
1.首先创建一个ID 差异表
这个表不是必须的,这里是为了清晰
SQL> create table hawa.prof as select NUMUSERID from hawa.hw_user where 1=0;
Table created.
Elapsed: 00:00:00.16
2.根据主键找到差异记录
注意这里取决于你的数据库产生差异的原因,我的差异由于初始数据不同步,即A 全包含B
并且,A>B。
SQL> insert into hawa.prof
2 select * from
3 (
4 select NUMUSERID from hawa.HW_USERPROFILE
5 minus
6 select NUMUSERID from hawa.HW_USERPROFILE@authaa)
7 /
263 rows created.
Elapsed: 00:00:32.49
3.创建记录表
SQL> create table hawa.missing_rows_hw_userprofile
2 as
3 select * from hawa.hw_userprofile where 1=0;
Table created.
Elapsed: 00:00:00.12
4.创建位置(Location)表
注意这里Oracle 需要记录缺失方向, 和具体记录的ROWID, 这个ROWID 来自
missing_rows_hw_userprofile。
SQL> create table hawa.MISSING_LOC_hw_userprofile (
2 present VARCHAR2(128),
3 absent VARCHAR2(128),
4 r_id ROWID);
Table created.
Elapsed: 00:00:00.04
4.根据差异信息查询到完整信息
SQL> insert into hawa.missing_rows_hw_userprofile
2 select * from hawa.hw_userprofile where NUMUSERID in
3 (select * from hawa.prof);
263 rows created.
Elapsed: 00:00:00.06
SQL> commit;
Commit complete.
Elapsed: 00:00:00.02
5.构造位置信息
注意这里的方向信息及ROWID 信息。
SQL> insert into hawa.MISSING_LOC_hw_userprofile
2 select 'AVATAR.COOLYOUNG.COM.CN','AUTHAA.COOLYOUNG.COM.CN',rowid from
hawa.missing_rows_hw_userprofile;
263 rows created.
Elapsed: 00:00:00.00
SQL> commit;
Commit complete.
Elapsed: 00:00:00.06
6.纠正数据冲突
SQL> BEGIN DBMS_RECTIFIER_DIFF.RECTIFY(
2 SNAME1 =>'HAWA',
3 ONAME1 =>'HW_USERPROFILE',
4 REFERENCE_SITE =>'AVATAR.COOLYOUNG.COM.CN',
5 SNAME2 =>'HAWA',
6 ONAME2 =>'HW_USERPROFILE',
7 COMPARISON_SITE =>'AUTHAA.COOLYOUNG.COM.CN',
8 COLUMN_LIST =>NULL,
9 MISSING_ROWS_SNAME =>'HAWA',
10 MISSING_ROWS_ONAME1 =>'MISSING_ROWS_HW_USERPROFILE',
11 MISSING_ROWS_ONAME2 =>'MISSING_LOC_HW_USERPROFILE',
12 MISSING_ROWS_SITE =>'AVATAR.COOLYOUNG.COM.CN',
13 COMMIT_ROWS =>100
14 );
15 END;
16 /
PL/SQL procedure successfully completed.
Elapsed: 00:00:03.53
7.验证结果
SQL> select count(*) from hawa.HW_USERPROFILE;
COUNT(*)
----------
1746300
Elapsed: 00:00:02.22
SQL> select count(*) from hawa.HW_USERPROFILE@authaa;
COUNT(*)
----------
1746300
Elapsed: 00:00:00.21
SQL> select count(*) from hawa.HW_USERPROFILE;
COUNT(*)
----------
1746300
Elapsed: 00:00:00.59
SQL>select count(*) from hawa.HW_USERPROFILE@authaa;
COUNT(*)
----------
1746300
Elapsed: 00:00:00.20
SQL> select NUMUSERID from hawa.HW_USERPROFILE
2 minus
3 select NUMUSERID from hawa.HW_USERPROFILE@authaa ;
no rows selected
Elapsed: 00:00:23.51
SQL>
五、 解决数据冲突-dbms_rectifier_diff 包
很多时候在高级复制中可能存在数据冲突和不一致现象。
Oracle 提供的dbms_rectifier_diff 包可以用于解决该冲突。
以下通过实例来说明一下该Package 的用法。
1.创建复制组及复制对象
SQL> execute dbms_repcat.create_master_repgroup('rep_tt');
PL/SQL procedure successfully completed
SQL> select gname,master,status from dba_repgroup;
GNAME MASTER STATUS
------------------------------ ------ ---------
REP_TT Y QUIESCED
SQL> execute dbms_repcat.create_master_repobject(sname=>'hawa',oname=>'test',
type=>'table',use_existing_object=>true,gname=>'rep_tt',copy_rows=>false);
PL/SQL procedure successfully completed
SQL>
SQL> execute dbms_repcat.generate_replication_support('hawa','test','table');
PL/SQL procedure successfully completed
SQL> select gname, master, status from dba_repgroup;
GNAME MASTER STATUS
------------------------------ ------ ---------
REP_TT Y QUIESCED
SQL> select * from dba_repobject;
SNAME ONAME TYPE STATUS GENERATION_STATUS ID OBJECT_COMMENT GNAME
MIN_COMMUNICATION REPLICATION_TRIGGER_EXISTS INTERNAL_PACKAGE_EXISTS
GROUP_OWNER NESTED_TABLE
------------------------------ ------------------------------ ---------------- ---------- -----------------
---------- -------------------------------------------------------------------------------- -----------------
HAWA TEST TABLE VALID GENERATED 8620 REP_TT Y Y Y PUBLIC N
HAWA TEST$RP PACKAGE VALID 8641 SYSTEM-GENERATED: REPLICATION REP_TT
PUBLIC
HAWA TEST$RP PACKAGE BODY VALID 8677 SYSTEM-GENERATED: REPLICATION
REP_TT PUBLIC
3 rows selected
SQL>
SQL> execute
dbms_repcat.add_master_database(gname=>'rep_tt',master=>'AUTHAA.COOLYOUNG.C
OM.CN',use_existing_objects=>true, copy_rows=>false, propagation_mode =>
'synchronous');
PL/SQL procedure successfully completed
SQL> execute dbms_repcat.resume_master_activity('rep_tt',true);
PL/SQL procedure successfully completed
SQL> select * from dba_repgroup;
SNAME MASTER STATUS SCHEMA_COMMENT GNAME FNAME
RPC_PROCESSING_DISABLED OWNER
-------- ------------------ ---- ------ ---- ---- -----------------------------------------------
REP_TT Y NORMAL REP_TT N PUBLIC
2.创建保存冲突数据的数据表
a.missing_rows 表用以保存冲突行
SQL> create table hawa.missing_rows_test
2 as
3 select * from hawa.test where 1=0;
Table created
b.用于保存缺失行位置及rowid
SQL> create table hawa.MISSING_LOCATION_TEST (
2 present VARCHAR2(128),
3 absent VARCHAR2(128),
4 r_id ROWID);
Table created
3.使用dbms_rectifier_diff.DIFFERENCES 查找缺失记录
SQL> begin dbms_rectifier_diff.DIFFERENCES(
2 SNAME1 =>'HAWA',
3 ONAME1 =>'TEST',
4 REFERENCE_SITE =>'AVATAR.COOLYOUNG.COM.CN',
5 SNAME2 =>'HAWA',
6 ONAME2 =>'TEST',
7 COMPARISON_SITE =>'AUTHAA.COOLYOUNG.COM.CN',
8 WHERE_CLAUSE =>NULL,
9 COLUMN_LIST =>NULL,
10 MISSING_ROWS_SNAME =>'HAWA',
11 MISSING_ROWS_ONAME1 =>'MISSING_ROWS_TEST',
12 MISSING_ROWS_ONAME2 =>'MISSING_LOCATION_TEST',
13 MISSING_ROWS_SITE =>'AVATAR.COOLYOUNG.COM.CN',
14 MAX_MISSING =>500,
15 COMMIT_ROWS =>100
16 );
17 end;
18 /
PL/SQL procedure successfully completed
冲突记录被保存在我们创建的指定表中
SQL> select count(*) from hawa.missing_rows_test;
COUNT(*)
----------
172
共有172 条差异记录
SQL> select count(*) from hawa.test;
COUNT(*)
----------
548
SQL> select count(*) from hawa.test@authaa;
COUNT(*)
----------
376
SQL> select count(*) from hawa.missing_location_test;
COUNT(*)
----------
172
4.使用DBMS_RECTIFIER_DIFF.RECTIFY 进行数据整合
首先需要注意的是:
RECTIFY 过程使用DIFFERENCES 产生的数据进行数据调整。
在第一个表中存在,在第二个表中不存在的数据将被插入第二张表。
在第二个表中存在,在第一个个表中不存在的数据将被从第二张表中删除。
另外,在这个数据纠正过程中,你可以使用dbms_repcat.suspend_master_activity 将复制
组暂时挂起。
这样便于保证数据完整性。
但这不是必须的,如果复制一直激活,可能会有新的冲突出现。
SQL> BEGIN DBMS_RECTIFIER_DIFF.RECTIFY(
2 SNAME1 =>'HAWA',
3 ONAME1 =>'TEST',
4 REFERENCE_SITE =>'AVATAR.COOLYOUNG.COM.CN',
5 SNAME2 =>'HAWA',
6 ONAME2 =>'TEST',
7 COMPARISON_SITE =>'AUTHAA.COOLYOUNG.COM.CN',
8 COLUMN_LIST =>NULL,
9 MISSING_ROWS_SNAME =>'HAWA',
10 MISSING_ROWS_ONAME1 =>'MISSING_ROWS_TEST',
11 MISSING_ROWS_ONAME2 =>'MISSING_LOCATION_TEST',
12 MISSING_ROWS_SITE =>'AVATAR.COOLYOUNG.COM.CN',
13 COMMIT_ROWS =>100
14 );
15 END;
16 /
PL/SQL procedure successfully completed
SQL> select count(*) from hawa.test@authaa;
COUNT(*)
----------
548
SQL> select count(*) from hawa.test;
COUNT(*)
----------
548
数据矫正完成以后,数据会自动从missing_rows 表中删除。
SQL> select count(*) from hawa.missing_rows_test;
COUNT(*)
----------
0
SQL>
六、 MVR 的概念和构架
Oracle 提供两种不同的复制方法:多主复制(multimaster replication)和物化视图复制
(materialized view replication)。还可以通过两种复制的组合构成混合复制。
本文主要描述物化视图复制,也就是MVR,由于物化视图复制中的主站点就是多主复制中
的站点,因此也会对相应的多主复制中涉及到的内容作相应的说明。
一、物化视图的概念和体系结构
Oracle 的物化视图主要用在两个方面:高级复制和数据仓库。在高级复制环境中,物化视图
用于复制数据到非主体站点。在数据仓库环境中,物化视图用于对代价昂贵的查询进行缓存。
下面讨论物化视图在高级复制环境中的使用。
1.物化视图是什么
物化视图(materialized view)是主体对象在某一时间点上的复制品。这个主体对象即可以
是主体站点(master site)上的一个主表,也可以是物化视图站点(materialized view site)
上的一个主物化视图。在多主复制中,一个站点上的表被其他主体站点连续不断的更新(这
个也是要分同步和异步的,异步情况下也是类似于refresh 这样的定时push),而物化视图
则是从一个主体站点或主物化视图站点批量的进行更新(也叫做刷新refresh)。
当物化视图进行快速刷新时(fast refresh),Oracle 会检查主表(master table)或主物化
视图(master materialized view)自上次刷新以来的所有改变,并将其应用到物化视图上。
因此,如果主体对象自上次刷新以来存在一些改变,则刷新操作则会花费一定的时间把这些
改变应用到物化视图上。如果自上次刷新以来没有发生任何变化,则物化视图刷新操作会迅
速的完成。
2.为什么使用物化视图
你可以使用物化视图来完成以下目标:
减轻网络负载;
创建一个Mass Deployment 环境;
数据子集;
Disconnected Computing。
(1) 减轻网络负载:
你可以通过物化视图将数据分布到许多站点,所有用户不需要再访问一个数据库服务器,负
载被分散到多个数据库服务器上。和多主复制不同的是,你可以根据需要,只复制表中的一
部分字段或者表中的一部分数据,从而降低了每次复制的数据量。
多主复制也可以分布网络负载,但与物化视图相比它对网络的要求要严格得多。由于多主复
制各个站点间采用的是网状连接,每个站点和其他所有的站点都有通信,而且多主复制一般
用于提供实时或接近实时的复制,这会导致很高的网络流量,对于网络状况要求比较严格。
物化视图采用高效的批量更新方式,从一个主体站点或一个主物化视图站点获得更新。和多
主复制的连续通信不一样,物化视图复制只需要周期性的刷新,从而对网络的要求大大降低。
(2) 创建Mass Deployment 环境:
展开模板(Deployment templete)允许你在本地预先建立物化视图环境。你可以利用展开
模板快速简便的展开物化视图环境。你可以不用修改展开模板,而是利用参数来建立不同用
户的客户化数据集。
(3) 数据子集(Data subsetting):
物化视图允许你的复制建立在列(column)或者行(row-level)的基础上,而多主复制需
要复制整张表。通过使用Data subsetting,对于每个站点你可以仅复制满足本站点需要的
数据。
(4) Disconnected Deployment:
物化视图不需要专用网络连接。你可以利用job 的调度机制完成物化视图的定时自动刷新,
你也可以在需要的时候手工刷新物化视图。而这第二种方法是在笔记本上运行应用程序的一
种理想解决方案。
3.物化视图的分类
物化视图分为只读、可更新和可写三类。不能对只读物化视图进行DML 操作
(INSERT/UPDATE/DELETE),对于可更新和可写物化视图则可以进行DML 操作。
注意:对于只读、可更新和可写物化视图,定义物化视图的查询语句必须包含主体对象中的
所有主键列。
(1) 只读物化视图
在建立物化视图时,省略FOR UPDATE 语句建立只读物化视图。除了不需要属于一个物化
视图组之外,只读物化视图的许多机制都和可更新物化视图相同。
使用只读物化视图可以消除在主体站点或者主物化视图站点上由物化视图引入的数据冲突,
这个优点的代价是只读物化视图不能进行dml 操作。
建立只读物化视图的例子如下:
CREATE MATERIALIZED VIEW hr.employees AS SELECT * FROMhr.employees@orc1.world;
注意:使用只读物化视图只能消除由物化视图站点引入的冲突,并不意味着使用只读物化视
图就不会有冲突产生,后面会举例详细说明。
(2) 可更新物化视图
在建立物化视图时,指明FOR UPDATE 语句建立可更新物化视图。为了可更新物化视图的
修改在刷新时可以被“推回”(push pack)主体对象,可更新物化视图必须属于一个物化视
图组。
由于可更新物化视图允许数据的修改,因此可以降低主体站点的负载。
下面是建立可更新物化视图的例子:
CREATE MATERIALIZED VIEW hr.departments FOR UPDATE AS
SELECT * FROM hr.departments@orc1.world;
下面的语句建立一个物化视图组:
BEGIN
DBMS_REPCAT.CREATE_MVIEW_REPGROUP (
gname => 'hr_repg',
master => 'orc1.world',
propagation_mode => 'ASYNCHRONOUS');
END;
/
下面的语句将物化视图hr.departments 加入到物化视图组hr_repg 中,使得物化视图
hr.departments 可更新。
BEGIN
DBMS_REPCAT.CREATE_MVIEW_REPOBJECT (
gname => 'hr_repg',
sname => 'hr',
oname => 'departments',
type => 'SNAPSHOT',
min_communication => TRUE);
END;
/
注意:
1. 不要在建立可更新物化视图时使用列的别名,否则,在将物化视图加入到物化
视图组的时候会发生错误。
2. 主表或主物化视图列上的默认值不会自动应用到可更新物化视图上。
3. 可更新物化视图不支持DELETE CASCADE 操作。
(3) 可写物化视图
可写物化视图指出FOR UPDATE 语句,但是没有加入到物化视图组。用户可以对可写物化
视图执行DML 操作,但是在执行刷新操作时,修改不会被“推回”,因此所有的修改在刷新
后全部丢失。所有允许只读物化视图的情况也同样允许可写物化视图。
由于可写物化视图很少使用,因此以后大部分内容都只涉及只读物化视图和可更新物化视
图。
4.物化视图可用性
Oracle 提供几种不同类型的物化视图,以满足各种复制环境的需要。
介绍下列物化视图以及它们使用的环境:
主键物化视图(Primary Key Materialized Views);
对象物化视图(Object Materialized Views);
ROWID 物化视图(ROWID Materialized Views);
复杂物化视图(Complex Materialized Views)。
当建立物化视图时,不管物化视图属于何种类型,总是给出方案名(schema),也就是查询
语句中表的所有者名称。例如:
CREATE MATERIALIZED VIEW hr.employees
AS SELECT * FROM hr.employees@orc1.world;
这个例子中,方案名hr 被明确指出。
(1) 主键物化视图
主键物化视图是默认的物化视图。如果主键物化视图是作为物化视图组的一部分建立的,且
指定了FOR UPDATE 语句,那么这个物化视图是可更新的,且这个物化视图组必须和主站
点中复制组的同名。另外,可更新物化视图必须和主复制组在不同的数据库中。
当修改发生后,修改的数据以行级为单位被传播,每行数据由主键确定(而不是ROWID)。
下面是一个创建可更新的主键物化视图的例子:
CREATE MATERIALIZED VIEW oe.customers FOR UPDATE AS
SELECT * FROM oe.customers@orc1.world;
主键物化视图可以包含一个子查询,因此你可以在建立物化视图时,建立所有数据的一个子
集,也就是说,建立物化视图时可以只选取你需要的数据行。子查询是嵌入在主查询中的查
询,因此你可以在建立物化视图时有超过一个的SELECT 语句。子查询可以是简单的WHERE
语句也可以是复杂的多层WHERE EXISTS 语句嵌套。如果主站点中的主对象建立了物化视
图日志表(materialized view log),那么一些包含特定类型子查询的主键物化视图仍然可以
快速(增量)刷新。快速刷新利用materialized view logs 只更新自上次刷新后被修改的记
录。
下面的物化视图包含一个WHERE 语句的子查询:
CREATE MATERIALIZED VIEW oe.orders REFRESH FAST AS
SELECT * FROM oe.orders@orc1.world o
WHERE EXISTS
(SELECT * FROM oe.customers@orc1.world c
WHERE o.customer_id = c.customer_id AND c.credit_limit > 10000);
这种类型的物化视图又叫做子查询物化视图。
(2) 对象物化视图
如果物化视图是基于对象表,并且在建立是指定了OF TYPE 语句,那么这个物化视图叫做
对象物化视图。对象物化视图的结构和对象表相同——对象物化视图由行对象(row objects)
组成,每一个行对象由一个对象标识列OID(object identifier)标识。
(3) ROWID 物化视图
为了后向兼容性,Oracle 除了默认的主键物化视图外,还支持ROWID 物化视图。ROWID
物化视图基于主对象中行记录的物理标识ROWID(physical row identifiers)。ROWID 物化
视图只被用在基于Oracle7 版本的主对象的物化视图,它不能被用于建立基于Oracle8 或更
高版本主站点的物化视图。
下面是一个建立ROWID 物化视图的例子:
CREATE MATERIALIZED VIEW oe.orders REFRESH WITH ROWID AS
SELECT * FROM oe.orders@orc1.world;
(4) 复杂物化视图
物化视图的定义必须满足某种约束,才能执行快速刷新。如果你需要的物化视图的定义查询
语句更为一般化,不能满足限制条件,那么这个物化视图是复杂的,并且不能执行快速刷新。
一般来说,如果一个物化视图的定义查询包含下列语句,则被认为是复杂物化视图:
CONNECT BY 语句;
例如:
CREATE MATERIALIZED VIEW hr.emp_hierarchy AS
SELECT LPAD(' ', 4*(LEVEL-1))||email USERNAME
FROM hr.employees@orc1.world START WITH manager_id IS NULL
CONNECT BY PRIOR employee_id = manager_id;
INTERSECT,MINUS 或UNION ALL 操作;
例如:
CREATE MATERIALIZED VIEW hr.mview_employees AS
SELECT employees.employee_id, employees.email
FROM hr.employees@orc1.world
UNION ALL
SELECT new_employees.employee_id, new_employees.email
FROM hr.new_employees@orc1.world;
在某些情况下的DISTINCT 和UNIQUE 关键字;
包含DISTINCT 和UNIQUE 关键字的并不都是复杂物化视图,简单物化视图(simple
materialized view)中也可以包含这两个关键字。下面的例子是建立一个包含DISTINCT 关
键字的复杂物化视图:
CREATE MATERIALIZED VIEW hr.employee_depts AS
SELECT DISTINCT department_id FROM hr.employees@orc1.world
ORDER BY department_id;
聚集操作;
如下例:
CREATE MATERIALIZED VIEW hr.average_sal AS
SELECT AVG(salary) "Average" FROM hr.employees@orc1.world;
连接不在子查询中的对象;
例如:
CREATE MATERIALIZED VIEW hr.emp_join_dep AS
SELECT last_name
FROM hr.employees@orc1.world e, hr.departments@orc1.world d
WHERE e.department_id = d.department_id;
某种情况下的UNION 操作。
例如:
CREATE MATERIALIZED VIEW oe.orders AS
SELECT order_total
FROM oe.orders@orc1.world o
WHERE EXISTS
(SELECT cust_first_name, cust_last_name
FROM oe.customers@orc1.world c
WHERE o.customer_id = c.customer_id
AND c.credit_limit > 50)
UNION
SELECT customer_id
FROM oe.orders@orc1.world o
WHERE EXISTS
(SELECT cust_first_name, cust_last_name
FROM oe.customers@orc1.world c
WHERE o.customer_id = c.customer_id
AND c.account_mgr_id = 30);
以及其他任何不满足特定约束条件的子查询。具体条件见“物化视图中的数据子集”(Data
Subsetting with Materialized Views)的物化视图子查询约束(Restrictions for Materialized
Views with Subqueries)
注意:如果可能,尽量避免使用复杂物化视图,因为复杂物化视图不能快速刷新,将会降低
网络性能。
对比简单物化视图和复杂物化视图:
为了某种应用,你可能需要考虑使用一个复杂物化视图。你有两种方法可以选择,它们各有
利弊,具体如下:
图一:复杂物化视图和简单物化视图对比
复杂物化视图:上图中方法A 展示了一个复杂物化视图。这个复杂物化视图在数据库Ⅱ中
展示出高效的查询性能,因为连接操作在物化视图刷新时已经完成。然而,由于是复杂物化
视图,必须执行完全刷新,这将极为可能比执行快速刷新要慢得多。
简单物化视图通过视图连接:上图中方法B 在DATABASEⅡ展示了两个简单物化视图,它们
通过一个视图执行连接操作。通过视图查询不可能有方法A 中查询复杂物化视图那样的性
能。然而,简单物化视图可以更加有效的使用快速刷新和物化视图日志(materialized view
logs)。
总的来说:
如果你很少刷新,且需要比较高的查询性能,则使用方法A。(complex materialized view)
如果你经常刷新,且可以牺牲查询性能,则使用方法B。(simple materialized view)
5.物化视图操作所需权限
三种不同类型的用户对物化视图执行操作:
建立者(creator):建立物化视图的用户。
刷新者(refresher):刷新物化视图的用户。
所有者(owner):拥有物化视图的用户。物化视图存在于所有者的方案(schema)中。
一个用户对物化视图可以执行所有的操作。然而,在一些复制环境中,不同的用户对物化视
图执行不同的操作。执行这些操作需要的权限取决于操作由同一个用户执行还是由不同的用
户执行。下面详细解释所需权限。
注意:下文没有包括用重写查询(query rewrite)选项来创建物化视图时所需要的权限。
(1) 创建者是所有者
如果一个物化视图的创建者同时也是一个物化视图的所有者,那么这个用户可以通过明确授
权或通过角色拥有下列权限来创建一个物化视图。
CREATE MATERIALIZED VIEW 或者CREATE ANY MATERIALIZED VIEW 权限;
CREATE TABLE 或者CREATE ANY TABLE 权限;
如果数据库兼容性在8.1.0 以下,需要CREATE VIEW 或者CREATE ANY VIEW 权限;
对主站点上对象和物化视图日志的SELECT 权限或者SELECT ANY TABLE 系统权限。如果主
站点不是本地数据库,则SELECT 权限必须授权给一个主站点用户,这个用户就是物化视图
站点通过数据库链(database link)连接到主站点的用户(数据库链创建语句中CONNECT TO
关键字后面跟的用户)。
(2) 创建者不是所有者
如果物化视图的创建者不是所有者,必须授予创建者和所有者某种权限才能创建物化视图。
创建者的权限可以直接授权或通过角色授权,但是所有者的权限必须通过明确授权获得。也
就是说,所有者的权限不能通过角色获得。
创建者:
CREATE ANY MATERIALIZED VIEW 系统权限
所有者:
CREATE TABLE 或者CREATE ANY TABLE 权限;
如果数据库兼容性在8.1.0 以下,需要CREATE VIEW 或者CREATE ANY VIEW 权限;
对主站点上对象和物化视图日志的SELECT 权限或者SELECT ANY TABLE 系统权限。如果主
站点不是本地数据库,则SELECT 权限必须授权给一个主站点用户,这个用户就是物化视图
站点通过数据库链(database link)连到主站点的用户(数据库链创建语句中CONNECT TO
关键字后面跟的用户)。
(3) 刷新者是所有者
如果一个物化视图的刷新者同时也是物化视图的拥有者,这个用户需要主站点上对象和物化
视图日志的SELECT 权限或者SELECT ANY TABLE 系统权限。如果主站点不是本地数据库,
则SELECT 权限必须授权给一个主站点用户,这个用户就是物化视图站点通过数据库链
(database link)连到主站点的用户(数据库链创建语句中CONNECT TO 关键字后面跟的
用户)。权限可以通过直接授权或通过角色授权。
(4) 刷新者不是所有者
如果物化视图的刷新者不是所有者,必须授予刷新者和所有者某种权限。这些权限可以直接
授权或通过角色授权。
刷新者:
ALTER ANY MATERIALIZED VIEW 系统权限。
所有者:
主站点上对象和物化视图日志的SELECT 权限或者SELECT ANY TABLE 系统权限。如果主站
点不是本地数据库,则SELECT 权限必须授权给一个主站点用户,这个用户就是物化视图站
点通过数据库链(database link)连到主站点的用户(数据库链创建语句中CONNECT TO
关键字后面跟的用户)。
6.物化视图中的数据子集
在某些情况下,你可能希望你的物化视图反映主表或者主物化视图中数据的子集。通过使用
WHERE 语句,行子集允许你包含主表或者主物化视图中你想要的行记录。列子集允许你从
主表或者主物化视图中只包含你所需要的列。在创建物化视图时,通过在SELECT 语句中明
确指出所要选取的列来实现列子集。如果你使用展开模板来创建你的物化视图,那么你可以
在可更新物化视图上定义列子集。
(1) 使用数据子集的一些原因
降低网络流量:在一个使用列子集的物化视图中,只有满足物化视图定义中WHERE 条件语
句的修改才会传播到物化视图站点,因此减少了事务传输数量,降低了网络流量。
保护敏感数据:用户只能查看满足物化视图查询定义的数据。
减少资源需要:如果物化视图建立在笔记本上,则硬盘与服务器上的硬盘相比要小得多。数
据子集可以显著的减少存储空间。
提高刷新性能:由于较少的数据传播到物化视图站点,刷新执行的更加迅速。这一点对于那
些需要通过拨号连接来刷新物化视图的用户十分重要。
例如: 下面语句基于oe.orders@orc1.world 主表创建一个物化视图, 而且只包括
sales_rep_id 等于173 的记录。
CREATE MATERIALIZED VIEW oe.orders REFRESH FAST AS
SELECT * FROM oe.orders@orc1.world
WHERE sales_rep_id = 173;
主表中sales_rep_id 不等于173 的记录被排除出物化视图。
(2) 带子查询的物化视图
上面的例子是针对单个表的。如果创建基于多个表的物化视图,则定义和维护这些物化视图
相对来说困难得多。主要包括多对一子查询、一对多子查询、多对多子查询以及包含UNION
操作的子查询几种。这些物化视图比较复杂,而且在实际复制中不经常使用,因此这里不再
详细描述。如果对这部分有兴趣,请参阅Oracle9i Advanced Replication 3-18 Materialized
Views with Subqueries 部分。下面描述一下建立快速刷新子查询物化视图的条件。
物化视图子查询约束
带子查询的物化视图为了能达到快速刷新的能力,必须满足许多约束条件,具体如下:
必须是主键物化视图;
物化视图日志必须包括某些在子查询中出现的列;
如果子查询是多对多或一对多查询,连接列中非主键的部分必须包括在物化视图日志中,多
对一子查询没有这个约束;
子查询必须是肯定条件,比如,你可以使用EXISTS,但是不能使用NOT EXISTS;
子查询必须使用EXISTS 连接到嵌套层(nested level),不能使用IN;
每张表只允许一个EXISTS 表达式;
连接表达式必须采用精确匹配或等于连接;
在子查询中,每张表只能被连接一次;
在嵌套层(nested level)中,每张表必须有主键存在;
嵌套层(nested level)只能参考比它高的层中的表;
子查询可以包含AND 操作,但是每个OR 操作只能连接“能确定一条记录”的列,子查询
中多个OR 运算可以通过AND 连接;
子查询中的所有表必须在同一个主体站点或主物化视图站点中。
7.决定物化视图的快速刷新能力
为了检测所创建的带子查询的物化视图是否满足上面提到的建立快速刷新物化视图的种种
约束,在创建时,如果违反任何约束条件,则Oracle 会返回错误提示。如果在建立物化视
图时指明强制刷新(force refresh),则不会收到任何错误信息。因为在强制刷新时,如果
不能执行快速刷新的话,Oracle 会自动执行完全刷新(complete refresh)。
你也可以通过DBMS_MVIEW 包中的EXPLAIN_MVIEW过程来检测已存在的物化视图甚至是
还没有建立的物化视图的一些信息,具体信息如下:
物化视图的各种能力;
对于这个物化视图来说每种能力是否可能;
如果不可能,给出导致这种能力不可能的原因;
这些信息可以存储在varray 中,也可以存储在MV_CAPABILITIES_TABLE 表中。如果你希
望把信息存储到表中,那么你必须在执行EXPLAIN_MVIEW 存储过程以前, 执行
ORACLE_HOME/rdbms/admin 目录下的utlxmv.sql 脚本。
例如:检查oe.orders 物化视图的能力输入:
EXECUTE DBMS_MVIEW.EXPLAIN_MVIEW ('oe.orders');
或者如果物化视图不存在,你可以输入你希望建立的物化视图的查询语句:
BEGIN
DBMS_MVIEW.EXPLAIN_MVIEW ('SELECT * FROM oe.orders@orc1.world o
WHERE EXISTS (SELECT * FROM oe.customers@orc1.world c
WHERE o.customer_id = c.customer_id AND c.credit_limit > 500)');
END;
/
查询MV_CAPABILITIES_TABLE 表得到结果,如下例:
SQL> set linesize 110
SQL> col RELATED_TEXT format a60
SQL> select capability_name, possible, related_text from mv_capabilities_table;
CAPABILITY_NAME P RELATED_TEXT
------------------------------ - -------------------------------------
PCT N
REFRESH_COMPLETE Y
REFRESH_FAST N
REWRITE N
PCT_TABLE N 此上下文不支持对象数据类型
REFRESH_FAST_AFTER_INSERT N OE.CUSTOMERS
REFRESH_FAST_AFTER_INSERT N OE.ORDERS
REFRESH_FAST_AFTER_ONETAB_DML N
REFRESH_FAST_AFTER_ANY_DML N
REFRESH_FAST_PCT N
REWRITE_FULL_TEXT_MATCH N OE.ORDERS
REWRITE_FULL_TEXT_MATCH N OE.CUSTOMERS
REWRITE_FULL_TEXT_MATCH N 此上下文不支持对象数据类型
REWRITE_PARTIAL_TEXT_MATCH N
REWRITE_GENERAL N
REWRITE_PCT N
已选择16 行。
8.多级物化视图(Multitier Materialized Views)
物化视图的创建可以基于表,也可以基于其他物化视图,这种物化视图叫做多级物化视图
(multitier materialized views)。这种基于其他物化视图的物化视图可以是只读的(read
only)也可以是可更新的(updatable)。
当使用多级物化视图时,基于主体表的物化视图叫做第一层物化视图(level 1 materialized
view)。基于第一层物化视图的物化视图叫做第二层物化视图(level 2 materialized view)。
下一层是第三层,依此类推。
作为其他物化视图的主对象的物化视图叫做主物化视图(master materialized view)。处在
任何一层的物化视图都可以成为主物化视图,而且可以存在多个其他的物化视图基于同一个
主物化视图。
主物化视图和主站点中的主表起相同的作用。也就是说把第二层物化视图上的改变“推到”
第一层物化视图上的操作和把第一次物化视图上的改变“推到”主表上的操作是完全一样的。
在主物化视图站点必须注册一个接收者(receiver)。在多层物化视图站点中接收者负责接受
和应用来自主物化视图站点传播者的延迟事务。
多层物化视图(Multitier materialized views)在设计复制环境时提供了很高的灵活性。一些
物化视图站点不需要复制主表中所有的数据,实际上,这些站点可能根本没有足够的空间存
储这些数据。另外,只复制较少的数据意味着在网络上活动的数据也较少。
使用多层物化视图的限制条件:
主物化视图和基于主物化视图的物化视图都必须满足下列条件:
1) 必须是主键物化视图;
2) 所在数据库兼容性等于或者高于9.0.1。
主物化视图的一些限制。下列类型的物化视图不能作为可更新物化视图的主物化视图。
1) ROWID 物化视图;
2) 复杂物化视图;
3) 只读物化视图。
不过这三种物化视图可以成为只读物化视图的主物化视图。
基于物化视图的可更新物化视图的额外限制:
1) 所属的物化视图组必须和主物化视图站点上的物化视图组同名;
2) 必须和主物化视图不在同一个数据库上;
3) 必须基于可更新物化视图,不能基于只读物化视图;
4) 主站点上的主物化视图组必须存在于PUBLIC 方案中。
9.包含用户定义类型的物化视图
Oracle 的复制支持用户自定义类型数据。Oracle 不但支持行对象(row object)和列对象
(column object)而且还支持collections 的复制。Collection 包括基于用户自定义类型的数
组(VARRAY)和嵌套表(nested table)。
使用用户自定义类型需要注意几点:
主站点和物化视图站点的数据库兼容性等于或高于9.0.1;
如果主对象包含用户自定义类型,则不能创建refresh-on-commit 物化视图;
高级复制不支持对象的继承。
物化视图复制中对用户自定义类型的要求和限制于多主环境中的限制比较类似,这里不再详
细描述,如果对这部分内容感兴趣,请参考Oracle9i Advanced Replication 3-36 Materialized
Views with User-Defined Types。
10.主站点的物化视图注册
11.主站点和主物化视图站点机制
12.物化视图站点机制
13.组织机制
14.刷新处理
三.展开模板(Deployment Templates)的概念和构架
四.多主复制和物化视图复制区别
附录一。多主体复制站点的配置步骤
以下操作如果不是明确指出,均在master 数据库中运行。
1。检查安装好的数据库是否支持高级复制:
SQL> select value from v$option where parameter='Advanced replication';
VALUE
----------------------------------------------------------------
TRUE
确保返回的结果是TRUE,如果是FALSE 则表示需要重新安装oracle 的高级复制部件。
2。确保数据库的初始化参数中global_name=true,同时因为高级复制依靠于JOB 来实现,
所以必须保证
job_queue_processes 参数大于0,我们可以设置为10。
确保init.ora 中包含一下初始化参数定义:
global_names = true
open_links = 4 (备注:一个process 需要4 个link,如果我们创建了多个dblink,并且同
时运行,那么可以把此参数设大,比如以下环境中我们应该设置为open_links = 8)
job_queue_processes = 10
3。用sysdba 权限分别登录master 和snap 数据库,检查双方的global_name,必须保证
两边的域名相同才可以建立正确的dblink。
select * from global_name;
假设显示结果是master.com,那么表示该数据库的域名是com。那么我们可以设置snap
库的global_name 是snap.com。
使用以下SQL 设置global_name:
alter database rename global_name to master.com;
4。创建一个PUBLIC DBLINK 连接到snap(此步骤可以省略)
CREATE PUBLIC DATABASE LINK "snap.com" USING '(DESCRIPTION = (ADDRESS_LIST =
(ADDRESS= (PROTOCOL = TCP)(Host = 10.1.6.124)(Port = 1521)))(CONNECT_DATA =
(SID = test1)(SERVER = DEDICATED)))';
运行以下SQL 检查dblink 创建是否成功,如果结果返回snap 的global_name 则表示成功
SQL> select * from global_name@snap.com;
GLOBAL_NAME
--------------------------------------------------------------------------------
SNAP.COM
5。创建repadmin 用户,用于管理高级复制
create user repadmin identified by repadmin default tablespace users temporary
tablespace temp;
execute dbms_defer_sys.register_propagator('repadmin');
grant execute any procedure to repadmin;
execute dbms_repcat_admin.grant_admin_any_repgroup('repadmin');
execute dbms_repcat_admin.grant_admin_any_schema(username => '"REPADMIN"');
grant comment any table to repadmin;
grant lock any table to repadmin;
grant select any dictionary to repadmin;
6。登录snap 数据库,重复上面的操作,创建public dblink 以及repadmin 用户
7。用repadmin 用户登录master,创建私有数据库连接
create database link "snap.com" connect to repadmin identified by repadmin;
如果第4 步省略了,没有创建公有数据库连接,则需要如下创建,在创建含有qualifier 的
多个数据库连接时也只能使用下面的方法:
create database link "snap.com@perday" connect to repadmin identified by repadmin
USING '(DESCRIPTION = (ADDRESS_LIST = (ADDRESS= (PROTOCOL = TCP)(Host =
10.1.6.124)(Port = 1521)))(CONNECT_DATA = (SID = test1)(SERVER = DEDICATED)))';
create database link "snap.com@perhour" connect to repadmin identified by repadmin
USING '(DESCRIPTION = (ADDRESS_LIST = (ADDRESS= (PROTOCOL = TCP)(Host =
10.1.6.124)(Port = 1521)))(CONNECT_DATA = (SID = test1)(SERVER = DEDICATED)))';
检查是否创建成功
SQL> select * from global_name@snap.com@perday;
GLOBAL_NAME
--------------------------------------------------------------------------------
SNAP.COM
8。创建主体复制组,添加复制对象,操作的数据库将称为主体定义站点
创建每天复制一次的组
execute dbms_repcat.create_master_repgroup(gname => 'rep_gp_day',group_comment
=> 'replcation perday',qualifier => '@PERDAY');
创建每小时复制一次的组
execute dbms_repcat.create_master_repgroup(gname => 'rep_gp_hour',group_comment
=> 'replcation perhour',qualifier => '@PERHOUR');
备注:以下操作只以rep_gp_day 复制组为例,对于rep_gp_hour 复制组则应该作相应更改
再执行下面的操作。
检查执行结果
select * from dba_repsites;
--用spool 生成批量执行的SQL
set feedback off;
set pagesize 0;
set heading off;
set verify off;
set linesize 1000;
set trimspool on;
spool filename.sql;
select 'execute dbms_repcat.create_master_repobject(sname=>''test_user'',oname=>'''
|| table_name || ''',type=>''table'',use_existing_object=>true,gname=>''rep_gp_day'');'
CREATE_SQL from tabs;
select 'dbms_repcat.generate_replication_support(''test_user'',''' || table_name ||
''',''table'');' GEN_SQL from tabs;
spool off;
set feedback on;
set pagesize 9999;
set heading on;
set verify on;
检查复制组状态
select gname, master, status from dba_repgroup;
如果该复制组已经处于normal 状态,那么在添加复制对象之前必须先停顿复制组,既将同
步组的状态由正常(normal)改为停顿(quiesced )
execute dbms_repcat.suspend_master_activity (gname => 'rep_gp_day');
运行上面生成的spool 文件,批量执行创建复制对象和生成复制支持
如果是单独创建复制对象,则是手工执行下面的SQL
execute dbms_repcat.create_master_repobject(sname=>'test_user',oname=>'account',
type=>'table',use_existing_object=>true,gname=>'rep_gp_day',copy_rows => false);
execute dbms_repcat.generate_replication_support('test_user','account','table');
备注: 如果所有的主体站点都是在Oracle815 以上的版本, 那么设置
generate_replication_support 中的generate_80_compatible 参数为false,默认是true。
检查执行结果
select * from dba_repobject;
9。添加主体库,这一步操作必须要求dblink 工作正常
execute dbms_repcat.add_master_database(gname=>'rep_gp_day',
master=>'snap.com@perday', use_existing_objects=>true, copy_rows=>false,
propagation_mode => 'asynchronous');
select * from user_jobs;
execute dbms_repcat.resume_master_activity('rep_gp_day',false);
select gname, master, status from dba_repgroup;
如果上述的检查结果显示status 不是normal 的,那么运行:
execute dbms_repcat.resume_master_activity('rep_gp_day',true);
10。添加PUSH 的任务(执行间隔为1 天1 次),如果是一小时一次,则是1/24,如果是一
分钟一次则是1/1440
begin
dbms_defer_sys.schedule_push (
destination => 'snap.com@perday',
interval => 'sysdate + 1',
next_date => sysdate,
parallelism => 1,
delay_seconds => 50);
end;
/
添加PURGE 的任务(执行间隔为1 分钟1 次)
begin
dbms_defer

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/35489/viewspace-85072/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/35489/viewspace-85072/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值