合併式複寫如何追蹤和列舉變更
初始化發行集或訂閱後,合併式複寫會追蹤並列舉已發行資料表中之資料的所有變更。透過觸發程序 (複寫會為每一個發行資料表建立) 及發行集和訂閱資料庫中的系統資料表追蹤變更。這些複寫系統資料表會使用指出應傳播哪些變更的中繼資料來擴展。同步處理期間執行「合併代理程式」時,變更由代理程式列舉,然後視需要套用到「發行者」和「訂閱者」。
變更追蹤
合併式複寫使用下列觸發程序和系統資料表來追蹤所有已發行資料表的變更:
MSmerge_ins_<GUID>:插入觸發程序 (此觸發程序和其他觸發程序的 GUID 值是從 sysmergearticles 衍生的)
MSmerge_upd_<GUID>:更新觸發程序
MSmerge_del_<GUID>:刪除觸發程序
MSmerge_contents
MSmerge_tombstone
MSmerge_genhistory
合併式複寫使用下列其他系統資料表來追蹤已篩選資料表的變更:
MSmerge_partition_groups
MSmerge_current_partition_mappings
MSmerge_past_partition_mappings
[!附註]
列出的系統資料表由資料庫中所有合併式發行集和訂閱使用;例如,如果發行集資料庫中有多個發行集,則 MSmerge_contents 包含所有發行集中發行項的資料列。
未篩選資料表的變更追蹤
系統資料表
用於未篩選和已篩選資料表的系統資料表包含下列中繼資料:
MSmerge_contents 包含在此資料庫的已發行資料表中插入或更新之每一資料列的資料列。
MSmerge_tombstone 包含從此資料庫的已發行資料表中刪除之每一資料列的資料列。
MSmerge_genhistory 每個生成集都包含一個資料列。生成集是傳遞至發行者或訂閱者的變更集合。每次執行合併代理程式,都會關閉生成集。資料庫的後續變更會加入一或多個開啟生成集。
變更追蹤處理
下列變更追蹤處理用於所有的未篩選資料表:
已發行資料表上發生插入或更新時,會引發 MSmerge_ins_<GUID> 或 MSmerge_upd_<GUID> 觸發程序,並會將一個資料列插入到 MSmerge_contents 系統資料表中。MSmerge_contents 的 rowguid 資料行包含已插入或已更新資料列的 GUID,此表示下一次發生同步處理時,使用者資料表中對應的已插入或已更新資料列應被傳送到「發行者」或「訂閱者」。如果使用者資料表中的資料列上發生後續更新,則會更新 MSmerge_contents 中的資料列來反映此更新。
已發行資料表上發生刪除時,會引發 MSmerge_del_<GUID> 觸發程序,並且一個資料列會插入 MSmerge_tombstone 系統資料表中。MSmerge_tombstone 的 rowguid 資料行包含已刪除資料列的 GUID,此表示下一次發生同步處理時,刪除應被傳送到使用者資料表中對應的已刪除資料列之「發行者」或「訂閱者」。如果 MSmerge_contents 中參考了已刪除資料列 (因為上次同步處理之後已插入或更新了該資料列),資料列則會從 MSmerge_contents 中刪除。
已篩選資料表的變更追蹤
系統資料表
除了上一節描述的系統資料表外,發行集資料庫中還有三個資料表包含追蹤已篩選資料表變更的中繼資料。
MSmerge_partition_groups 針對發行集內定義的每個資料分割均包含一個資料列。資料分割可以:
使用 sp_addmergepartition 或 [發行集屬性] 對話方塊的 [資料分割] 頁面明確地定義。
在訂閱者同步處理時自動建立 (如果訂閱者要求一個在 MSmerge_partition_groups 中還沒有項目的資料分割)。
針對 MSmerge_contents 與 MSmerge_partition_groups 中每個唯一的資料列組合,MSmerge_current_partition_mappings 都會有一個資料列。例如,使用者資料表中的一個資料列若是屬於兩個資料分割,則在資料列更新時,會在 MSmerge_contents 插入一個資料列以反映更新,並在 MSmerge_current_partition_mappings 插入兩個資料列,以表示更新的資料列屬於兩個資料分割。
針對不再屬於給定資料分割的每個資料列,MSmerge_past_partition_mappings 中就會有一個資料列。有下列情況時,資料列會從資料分割中移出:
已刪除資料列。如果是從使用者資料表刪除資料列,就會在 MSmerge_tombstone 中插入一個資料列,並在 MSmerge_past_partition_mappings 中插入一或多個資料列。
資料行中用於篩選的值已經變更。例如,參數化篩選若是以公司總部所在的州別為基準,則在公司搬遷後,公司的資料列 (和其他資料表中的相關資料列) 就可能會從某個營業人員的資料分割中移出,並移入另一個業務人員的資料分割中。如果資料列更新之後不再屬於資料分割,則會在 MSmerge_contents 中插入或更新一個資料列,並在 MSmerge_past_partition_mappings 中插入一或多個資料列。
[!附註]
如果使用的是每個資料分割上具有一個訂閱的不重疊資料分割 (sp_addmergearticle 的 @partition_options 參數值為 3) ,則系統資料表 MSmerge_current_partition_mappings 和 MSmerge_past_partition_mappings 不會用於追蹤該資料列的資料分割對應,因為每個資料列僅屬於一個資料分割,且只能在一個「訂閱者」端變更。
變更追蹤處理
上述未篩選資料表的處理 (在「未篩選資料表的變更追蹤」一節) 也用於已篩選的資料表,此處理還具有下列功能:
已發行資料表上發生插入時,除了正在更新或正在插入 MSmerge_contents 的資料外,針對資料列所屬之每個資料分割,會將資料分割對應加入 MSmerge_current_partition_mappings 中。
已發行資料表上發生更新時,除了正在更新或正在插入 MSmerge_contents 的資料外,針對資料列所屬之每個資料分割,如果 MSmerge_current_partition_mappings 中不存在資料分割對應,則會加入一個。如果更新導致了某個資料列從一個資料分割移到另一個資料分割,則會在 MSmerge_current_partition_mappings 中更新一個資料列,且會在 MSmerge_past_partition_mappings 中加入一個資料列。
已發行資料表上發生刪除時,除了正在插入 MSmerge_tombstone 中的資料列外,會從 MSmerge_current_partition_mappings 中刪除一個資料列,而 MSmerge_past_partition_mappings 中會加入一個資料列。
變更列舉
系統資料表和程序
執行「合併代理程式」時,會使用許多系統資料表和預存程序列舉變更:
MSmerge_genhistory 每個生成集都包含一個資料列。生成集是傳遞至發行者或訂閱者的變更集合。每次執行合併代理程式,都會關閉生成集。資料庫的後續變更會加入一或多個開啟生成集。
sysmergesubscriptions 含有訂閱資訊,包括節點已傳送和收到的最後層代之變更記錄。在發行集資料庫中,此資料表包含此「發行者」的一個資料列和每個「訂閱者」的一個資料列。在訂閱資料庫中,此資料表通常包含此「訂閱者」和此「發行者」各一個資料列。
MSmerge_generation_partition_mappings 僅用於已篩選的資料表,記錄給定層代是否包含與給定資料分割相關的任何變更。發行集資料庫中的此資料表包含 MSmerge_genhistory 和 MSmerge_partition_groups 中每個唯一資料列組合的一個資料列。
開始列舉處理時 sp_MSmakegeneration 會關閉所有的開啟層代。
sp_MSenumchanges 列舉了資料表的變更 (許多名稱以 sp_MSenumchanges 開頭的相關程序也會在此處理中使用)。
sp_MSgetmetadata 判斷來自一個節點的變更是否應被套用到另一個節點,例如插入、更新或刪除。
變更列舉處理
在變更列舉期間會發生下列處理:
呼叫系統程序 sp_MSmakegeneration:
對於未篩選和已篩選的資料表,此程序會關閉在 MSmerge_genhistory 中參考的所有開啟層代 (已關閉的層代在 genstatus 資料行中值為 1 或 2) 。
對於已篩選的資料表,此程序會擴展系統資料表 MSmerge_generation_partition_mappings。如果層代包含與資料分割相關的一個或多個變更,則系統資料表中會插入一資料列。如果層代不包含與給定資料分割相關的任何變更,則 MSmerge_generation_partition_mappings 中不會插入資料列,而且不會為接收該資料分割的任何「發行者」列舉變更。
呼叫預存程序 sp_MSenumchanges 和相關程序。這些程序會列舉上次同步處理以來發生的變更。
程序首先會判斷列舉開始於哪個層代,這將視資料表 sysmergesubscriptions 中的資料行 sentgen (最後傳送的層代) 和 recgen (最後收到的層代) 而定。
例如,當判斷必須為給定的「發行者」列舉哪個層代的變更時,將比較「發行者」的 sentgen (儲存在發行集資料庫中) 和「訂閱者」的 recgen (儲存在訂閱資料庫中)。如果值相同 (表示「訂閱者」已成功接收從「發行者」傳送的最後層代),則會在 MSmerge_genhistory 中列舉從下次層代開始的變更。如果值不相同,則由兩個值中較小的那個來確定是否所有需要的變更都已傳送。
然後程序列舉變更:
對於未篩選的資料表,會列舉 sentgen 或 recgen 中層代之後層代包含的所有變更:MSmerge_genhistory 會聯結到 MSmerge_contents 和 MSmerge_tombstone 以便判斷必須傳送哪些變更。
對於已篩選的資料表,MSmerge_generation_partition_mappings 會聯結到:MSmerge_current_partition_mappings 和 MSmerge_contents;MSmerge_past_partition_mappings 和 MSmerge_tombstone,以便判斷哪些變更與「訂閱者」收到的資料分割相關。
會呼叫 sp_MSgetmetadata 預存程序來判斷是否應套用變更,例如插入、更新或刪除。此時,執行衝突偵測和解決;如需詳細資訊,請參閱<合併式複寫如何偵測並解決衝突>。
請參閱