共用方式為


合併複本如何偵測和解決衝突

合併複寫可讓多個節點進行自主資料變更,因此存在在一個節點上所做的變更可能與另一個節點上對相同資料所做的變更衝突的情況。 在其他情況下,合併代理程式會遇到錯誤,例如條件約束違規,而且無法將特定節點所做的變更傳播至另一個節點。 本文說明衝突的類型、如何偵測和解決衝突,以及影響偵測和解決的因素。

偵測和解決衝突

合併代理程式會使用lineage資料行來偵測系統資料表MSmerge_contents的衝突;如果已啟用某篇文章的資料行層級追蹤,也會使用COLV1資料行。 這些資料行包含插入或更新資料列或資料行的時間,以及合併式複寫拓蹼中的哪些節點對資料列或資料行進行了變更的中繼資料。 您可以使用 sp_showrowreplicainfo 系統預存程序來檢視此中繼資料。

當合併代理程式列舉在同步處理期間要套用的變更時,它會比較發行者和訂閱者上每個資料列的中繼資料。 合併代理程式會使用此中繼資料來判斷拓撲中多個節點的列或欄是否已變更,這表示潛在的衝突。 偵測到衝突之後,合併代理程式會啟動針對有衝突之項目指定的衝突解決程式,並使用該解析程式來判斷衝突勝出者。 獲勝的資料列會套用到「發行者」和「訂閱者」端,而失敗的資料列的數據會寫入衝突資料表中。

除非您已為文章選擇互動式衝突解決,否則合併代理程式會自動立即解決衝突。 如需詳細資訊,請參閱 Microsoft 複寫互動式衝突解析程式。 如果您使用合併複寫衝突檢視器手動變更衝突的勝出資料列,合併代理程式會在下次同步處理期間,將資料列的勝出版本套用至失敗的伺服器。

記錄已解決的衝突

合併代理程式根據衝突解析程式中的邏輯解決衝突之後,會根據衝突類型記錄衝突資料:

  • 對於 UPDATEINSERT 衝突,會將資料列的遺失版本寫入資料項目的衝突表格,該表格以 conflict_<PublicationName>_<ArticleName> 格式命名。 一般衝突資訊 (例如衝突類型) 會寫入表格 MSmerge_conflicts_info

  • 對於 DELETE 衝突,它會將資料列的遺失版本寫入 MSmerge_conflicts_info 資料表。 當刪除與更新操作競爭失敗時,因為刪除操作的資料列不保留任何資料,所以不會將任何內容寫入conflict_<PublicationName>_<ArticleName>

每篇文章的衝突資料表會依@conflict_loggingsp_addmergepublication參數指定值,在發行集資料庫、訂閱資料庫或兩者(預設值)中建立。 每個衝突表都與其所依據的條目具有相同的結構,但添加了 origin_datasource_id 列。 合併代理程式會從衝突資料表中刪除資料,如果資料早於發行集的衝突保留期間,該保留期間是使用 @conflict_retention 參數指定的 sp_addmergepublication (預設值為 14 天)。

複寫提供複寫衝突檢視器和預存程序 (sp_helpmergearticleconflictssp_helpmergeconflictrowssp_helpmergedeleteconflictrows) 來檢視衝突資料。 如需詳細資訊,請參閱 合併複寫的衝突解決

影響衝突解決的因素

有兩個因素會影響合併代理程式如何解決其偵測到的衝突:

  • 訂閱類型:客戶端或伺服器(訂閱是拉式或推式,這不會影響衝突解決的方式)。

  • 使用的衝突追蹤類型:列層級、直欄層級或邏輯記錄層級。

訂閱類型

當您建立訂用帳戶時,除了指定它是推送訂用帳戶還是提取訂用帳戶之外,您還可以指定它是用戶端訂用帳戶還是伺服器訂用帳戶;建立訂用帳戶之後,就無法變更類型 (在舊版的 SQL Server 中,用戶端和伺服器訂用帳戶分別稱為本機和全域訂用帳戶)。

具有指派優先順序值 (從 0.00 到 99.99) 的訂閱稱為伺服器訂閱;使用發行者優先順序值的訂用帳戶稱為用戶端訂用帳戶。 此外,具有伺服器訂閱的訂閱者可以將資料重新發佈給其他訂閱者。 下表摘要說明每種訂閱者類型的主要差異和用途。

類型 優先級值 使用過的
伺服器 由使用者指派 當您希望不同的訂閱者具有不同的優先順序時。
客戶 0.00,但資料變更在同步處理後會採用發行者的優先順序值。 當您希望所有訂閱者具有相同的優先順序,並且第一個訂閱者與發行者進行合併以成功化解衝突時。

若用戶端訂閱中的資料列發生變更,在同步訂閱之前,不會為該變更指派任何優先順序。 在同步處理期間,來自訂閱者的變更會指派發佈者的優先順序,並保留該優先順序以供後續同步處理。 從某種意義上說,發行者承擔變更的所有權。 此行為允許第一個訂閱者與發行者同步,以便在給定的資料列或資料行中,贏得與其他訂閱者的後續衝突。

當您變更伺服器訂閱中的資料列時,訂閱優先順序會儲存在變更的中繼資料中。 此優先順序值在與其他訂閱者的變更合併時,會隨變更的資料列移動。 這可確保較高優先順序訂用帳戶所做的變更不會因優先順序較低的訂用帳戶所進行的後續變更而遺失。

訂閱的明示的優先權值不能高於其發行者。 合併式複寫拓撲中的最上層發行者一律具有明確的優先順序值 100.00。 該發行集的所有訂閱都必須具有小於此值的優先順序值。 在重新發佈拓蹼中:

  • 如果訂閱者要重新發佈資料,則訂閱必須是優先順序值小於訂閱者上方的發行者的伺服器訂閱。

  • 如果訂閱者未重新發佈資料(因為它位於重新發佈樹的葉子層級),則訂閱必須是用戶端訂閱。

如需伺服器訂用帳戶和優先順序的詳細資訊,請參閱 根據訂用帳戶類型和指派的優先順序進行合併衝突解決的範例

延遲衝突提醒

具有不同衝突優先順序的伺服器訂閱可能會發生延遲衝突通知。 請考慮下列情境,其中發行者與低優先級訂閱者之間交換非衝突的變更,而當高優先級訂閱者與發行者同步時,這將導致衝突的變更:

  1. 發行者和名為 LowPrioritySub 的低優先順序訂閱者會在數個同步處理中交換變更,而不會發生衝突。

  2. 名為 HighPrioritySub 的高優先順序訂閱者已經有一段時間未與發行者同步,並且已對 LowPrioritySub 訂閱者所變更的相同資料行進行了修改。

  3. HighPrioritySub 訂閱者與發行者同步,因為它的優先順序高於 LowPrioritySub 訂閱者,所以在變更衝突中勝出。 發行者現在納入了 HighPrioritySub 訂閱者所做的變更。

  4. 然後,LowPrioritySub 訂閱者會與發布者同步合併,並由於與 HighPrioritySub 訂閱者的衝突而下載大量變更。

當優先順序較低的訂閱者對現在是衝突失敗者的相同列進行變更時,這種情況可能會成為問題。 這可能會導致此訂閱者所做的所有變更遺失。 此問題的潛在解決方案是確保所有訂閱者都具有相同的優先順序,除非商務邏輯另有規定。

追蹤等級

資料變更是否符合衝突的資格,取決於您為文章設定的衝突追蹤類型:列層級、欄層級或邏輯記錄層級。 如需邏輯記錄層級追蹤的詳細資訊,請參閱 進階合併複寫衝突 - 在邏輯記錄中解決

在列層級辨識衝突時,無論是否對相同資料行進行變更,對對應列所做的變更都會判定為衝突。 例如,假設對 Publisher 資料列的 address 資料行進行了一項變更,而對應 Subscriber 資料列的電話號碼資料行進行了第二次變更 (在相同的資料表中)。 使用資料列層級追蹤時,會偵測到衝突,因為對相同資料列進行了變更。 使用直欄層級追蹤時,不會偵測到任何衝突,因為已對相同列中的不同直欄進行變更。

對於列層級和欄層級追蹤,衝突的解決方式相同:整列資料會被衝突勝出的資料覆寫(對於邏輯記錄層級追蹤,解決方式取決於 article 屬性 logical_record_level_conflict_resolution)。

應用程式語意通常會決定要使用的追蹤選項。 例如,如果您要更新通常同時輸入的客戶資料,例如地址和電話號碼,則應選擇資料列層級追蹤。 如果在此情況下選擇資料行層級追蹤,則不會將一個位置的客戶地址和另一個位置的客戶電話號碼的變更偵測為衝突:資料會在同步處理時合併,而且會遺漏錯誤。 在其他情況下,更新來自不同網站的個別資料行可能是最合乎邏輯的選擇。 例如,兩個網站可能可以存取客戶的不同類型統計資訊,例如收入水準和信用卡購買的總金額。 選取欄層級追蹤可確保兩個網站都可以輸入不同欄的統計資料,而不會產生不必要的衝突。

備註

如果您的應用程式不需要資料行層級追蹤,建議您使用資料列層級追蹤 (預設值),因為它通常會帶來更好的同步處理效能。 如果使用資料列追蹤,基底資料表最多可以包含 1,024 個資料行,但必須從文章中篩選資料行,才能發佈最多 246 個資料行。 如果使用數據行追蹤,基表最多可以包含 246 個數據行。

衝突類型

雖然大部分的衝突都與更新有關 (一個節點的更新與另一個節點的更新或刪除衝突),但還有其他衝突類型。 本節中討論的每種類型的衝突都可能發生在合併處理的上傳階段或下載階段。 上傳處理是在特定合併工作階段中執行的變更的第一次協調,也是合併代理程式將變更從訂閱者複寫到發行者的階段。 在此處理期間偵測到的衝突稱為上傳衝突。 下載處理涉及將變更從發佈者移至訂閱者,並在上傳處理之後發生。 此處理階段期間的衝突稱為下載衝突。

如需衝突類型的詳細資訊,請參閱 MSmerge_conflicts_info,尤其是 conflict_typereason_code 資料行。

更新-更新衝突

當一個節點上的資料列 (或資料行或邏輯記錄) 的更新與另一個節點上相同資料列的另一個更新衝突時,合併代理程式會偵測更新/更新衝突。 在此情況下,預設解析器的行為是將資料列的獲勝版本傳送至失敗節點,並將失敗的資料列版本記錄在文章衝突資料表中。

更新-刪除衝突

當一個節點上的資料更新與另一個節點上的刪除衝突時,合併代理程式會偵測更新-刪除衝突。 在此情況下,合併代理程式會更新資料列;不過,當合併代理程式在目的地搜尋該資料列時,它找不到該資料列,因為它已被刪除。 如果獲勝者是更新資料列的節點,則會捨棄失敗節點的刪除,而合併代理程式會將新更新的資料列傳送給衝突失敗者。 合併代理程式會將資料列遺失版本的相關資訊記錄到資料表。MSmerge_conflicts_info

失敗的變更衝突

合併代理程式在無法套用特定變更時引發這些衝突。 這通常是因為發行者與訂閱者之間的條件約束定義不同,以及在條件約束上使用 NOT FOR REPLICATION(NFR)屬性。 範例包括:

  • 訂閱者的外部索引鍵衝突,當訂閱者端限制未標示為 NFR 時,可能會發生此衝突。

  • 發佈者與訂閱者之間的限制條件差異,且這些限制條件未標示為 NFR。

  • 訂閱者的相依物件不可用。 例如,如果您發佈檢視,但未發佈該檢視所相依的資料表,則如果您嘗試在訂閱者處插入該檢視,則會發生失敗。

  • 針對不符合主鍵和外鍵條件約束的發行集進行聯結篩選邏輯。 當 SQL Server 關聯式引擎嘗試遵循約束條件,但合併代理程式遵循文章之間的聯接篩選器定義時,可能會發生衝突。 合併代理程式無法在目的地節點套用變更,因為資料表層級條件約束,這會導致衝突。

  • 如果為文章定義身分資料行,且未使用自動化身分識別管理,則可能會因為唯一索引或唯一條件約束違規或主索引鍵違規而發生衝突。 如果兩個訂閱者對新插入的資料列使用相同的身分識別值,這可能會發生問題。 如需身分識別範圍管理的詳細資訊,請參閱 複寫身分資料行

  • 由於觸發程式邏輯的影響,導致合併代理程式無法在目的地資料表中插入資料列,從而發生衝突。 考慮在訂閱者處定義的更新觸發程式;該觸發程式未標示為 NFR,且在其邏輯中包含 ROLLBACK。 如果發生失敗,觸發程序會發出交易的 , ROLLBACK 這會導致合併代理程式偵測到失敗的變更衝突。