學習Advanced Replication(高階複製) -zt

tolywang發表於2007-12-03
一、 概述
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
)
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
;
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
;
COUNT(*)
----------
1746300
Elapsed: 00:00:00.20
SQL> select NUMUSERID from hawa.HW_USERPROFILE
2 minus
3 select NUMUSERID from
;
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
;
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
;
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 * FROM
;
注意:使用只讀物化檢視只能消除由物化檢視站點引入的衝突,並不意味著使用只讀物化視
圖就不會有衝突產生,後面會舉例詳細說明。
(2) 可更新物化檢視
在建立物化檢視時,指明FOR UPDATE 語句建立可更新物化檢視。為了可更新物化檢視的
修改在重新整理時可以被“推回”(push pack)主體物件,可更新物化檢視必須屬於一個物化視
圖組。
由於可更新物化檢視允許資料的修改,因此可以降低主體站點的負載。
下面是建立可更新物化檢視的例子:
CREATE MATERIALIZED VIEW hr.departments FOR UPDATE AS
SELECT * FROM
;
下面的語句建立一個物化檢視組:
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 被明確指出。
(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
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
;
(4) 複雜物化檢視
物化檢視的定義必須滿足某種約束,才能執行快速重新整理。如果你需要的物化檢視的定義查詢
語句更為一般化,不能滿足限制條件,那麼這個物化檢視是複雜的,並且不能執行快速重新整理。
一般來說,如果一個物化檢視的定義查詢包含下列語句,則被認為是複雜物化檢視:
CONNECT BY 語句;
例如:
CREATE MATERIALIZED VIEW hr.emp_hierarchy AS
SELECT LPAD(' ', 4*(LEVEL-1))||email USERNAME
FROM
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

UNION ALL
SELECT new_employees.employee_id, new_employees.email
FROM
;
在某些情況下的DISTINCT 和UNIQUE 關鍵字;
包含DISTINCT 和UNIQUE 關鍵字的並不都是複雜物化檢視,簡單物化檢視(simple
materialized view)中也可以包含這兩個關鍵字。下面的例子是建立一個包含DISTINCT 關
鍵字的複雜物化檢視:
CREATE MATERIALIZED VIEW hr.employee_depts AS
SELECT DISTINCT department_id FROM

ORDER BY department_id;
聚集操作;
如下例:
CREATE MATERIALIZED VIEW hr.average_sal AS
SELECT AVG(salary) "Average" FROM
;
連線不在子查詢中的物件;
例如:
CREATE MATERIALIZED VIEW hr.emp_join_dep AS
SELECT last_name
FROM
e, d
WHERE e.department_id = d.department_id;
某種情況下的UNION 操作。
例如:
CREATE MATERIALIZED VIEW oe.orders AS
SELECT order_total
FROM
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
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 條件語
句的修改才會傳播到物化檢視站點,因此減少了事務傳輸數量,降低了網路流量。
保護敏感資料:使用者只能檢視滿足物化檢視查詢定義的資料。
減少資源需要:如果物化檢視建立在筆記本上,則硬碟與伺服器上的硬碟相比要小得多。數
據子集可以顯著的減少儲存空間。
提高重新整理效能:由於較少的資料傳播到物化檢視站點,重新整理執行的更加迅速。這一點對於那
些需要透過撥號連線來重新整理物化檢視的使用者十分重要。
例如: 下面語句基於
主表建立一個物化檢視, 而且只包括
sales_rep_id 等於173 的記錄。
CREATE MATERIALIZED VIEW oe.orders REFRESH FAST AS
SELECT * FROM

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
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
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 "
" 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 "
" 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
8。建立主體複製組,新增複製物件,操作的資料庫將稱為主體定義站點
建立每天覆制一次的組
execute dbms_repcat.create_master_repgroup(gname => 'rep_gp_day',group_comment
=> 'replcation perday',qualifier =>
);
建立每小時複製一次的組
execute dbms_repcat.create_master_repgroup(gname => 'rep_gp_hour',group_comment
=> 'replcation perhour',qualifier =>
);
備註:以下操作只以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 =>
,
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/,如需轉載,請註明出處,否則將追究法律責任。

相關文章