此案例剛好發現觸發程序(trigger)對合併式複寫(merge replication)與交易式複寫(transaction replication)的影響。
有一個設定複寫的發行資料庫,部分資料表被設為交易式(transaction)複寫的發行項(article),另有部分資料表被設為合併式(merge)複寫的發行項,資料表皆同步到海外的另一部資料庫伺服器的同一個database上,但是交易式複寫卻常常發生以下錯誤訊息:
描述: Replication-複寫散發子系統: 代理程式 xxxxx-xxx-xxxx-xxxxxx-xx 失敗。套用複寫的命令時在訂閱者端找不到資料列。
此問題導致三不五時就要手動補資料或是重建複寫,本以為是海外IT人員又為了圖方便,所以人為去增刪訂閱者端的資料(因為以前也曾發生過),導致複寫機制出現問題,後來才發現是觸發程序在搞鬼。
因為使用交易式複寫時,會在使用訂閱者端使用預存程序(sp_MSdel_xxx / sp_MSins_xxx / sp_MSupd_xxx)來執行資料同步。
而使用合併式複寫時,會在使用訂閱者端使用觸發程序(MSmerge_del_xxx / MSmerge_ins_xxx / MSmerge_upd_xxx)來執行資料同步。
重點在於我所設定的合併式複寫中,其來源資料表本身就有包含trigger來對其他資料表(這些資料表又剛好為交易式複寫的發行項)進行資料的刪除及更新,當來源資料表設定為合併式複寫的發行項並同步到訂閱者時,預設trigger亦會跟著同步到訂閱者端,所以就會造成合併式複寫的發行項執行資料的刪除及修改時,也會異動到其他正在進行交易式複寫的發行項的資料,造成交易式複寫發生「在訂閱者端找不到資料列」的錯誤。
但若交易式複寫的來源資料表本身有包含trigger時,預設trigger並不會被同步到訂閱者端。
後來與開發人員討論後,在不影響應用程式運作下,將同步到海外DB伺服器的發行集全部改為交易式複寫,在訂閱者端找不到資料列的錯誤才未再發生。
【後記】:
前面所提到的例子是交易式複寫及合併式複寫同時使用時才發生訂閱端資料被誤刪,另外,若大型資料庫其複寫初始化訂閱是採用備份/還原方式的話,因為是整個來源資料庫還原,所以也要注意訂閱端的觸發程序(trigger)是否會誤刪資料喔!
Jay Huang