當 SQL Server 在不同的世代批次中處理子代和父代世代時,非聚合
本文可協助您解決 SQL Server 在不同的世代批次中處理子代和父代代時所發生的非聚合問題。
原始產品版本:SQL Server
原始 KB 編號: 308266
徵兆
在訂閱者端的子數據表中遺失 INSERT 命令可能會在下列情況下發生:
- 合併式復寫拓撲是階層式的,具有發行者、一或多個重新發行者,以及一或多個訂閱者。
- 合併式復寫發行集中有一或多個父發行項和子發行項,其中定義聯結篩選條件。
NOT FOR REPLICATION
這兩篇文章之間關聯性的重新發佈和訂閱者存在外鍵條件約束。- INSERT 到子發行項的產生中,會透過合併代理程序參數中指定的值,在與其相關聯的父代產生區隔開時
-DownloadGenerationsPerBatch
發生。 因此,合併代理程式會在與其相關聯的父代產生分開的批次中處理子代。 - 發行者與重新發行者之間的合併處理中斷,以及子代和父代批次的處理之間。
因應措施
合併式復寫架構不提供一種機制,可跨世代批次界限將父系和子系變更保持在一起。 若要解決此問題,您可以:
-UploadGenerationsPerBatch
將 和-DownloadGenerationsPerBatch
合併代理程式 參數增加到其最大值 2000,這幾乎消除了在與父發行項世代分開的批次中處理子發行項產生的可能性。
-或-
NOT FOR REPLICATION
拿掉重新發佈端外鍵條件約束上的屬性。 在此情況下,合併代理程式 無法將數據列插入子發行項,因為沒有相關聯的父發行項數據列。 不過,請記住,可能會有與此變更相關聯的效能降低。 如果 合併代理程式 無法插入這些子數據列,則必須重試這些變更。 合併代理程式 重試程式比批處理的一般模式低得多。
其他相關資訊
以下是發生此問題的更詳細事件序列。 和 -DownloadGenerationsPerBatch
合併代理程式 參數的-UploadGenerationsPerBatch
預設值是 100。 在下列範例中,假設 -UploadGenerationsPerBatch
和 -DownloadGenerationsPerBatch
參數尚未改變。
- INSERT 發生在最上層發行者中,成為子發行項和父發行項。 子發行項是發行集中具有另一個數據表外鍵條件約束的任何發行項,稱為父發行項。 這兩篇文章是由合併式復寫聯結篩選和重新發佈端的實際伺服器端外鍵條件約束所關聯,且訂閱者會以NOT FOR REPLICATION 屬性標示。 如果您不確定條件約束是否不適合復寫,您可以在數據表上執行 sp_help 預存程式。
- 子數據表中的 INSERT 會在層代 110 中發生(例如)。 父數據表中的 INSERT 會在層代 250 中發生(例如)。 這些世代之間的分隔大於
-DownloadGenerationsPerBatch
參數。 - publisher-republisher 合併代理程式 處理包含層代 101 到 200 的世代批次。 成功處理此批次,並將這些世代中的相關聯變更下載至重新發行者之後,publisher-republisher 合併代理程式 會中斷。 中斷發生在 合併代理程式 可以處理層代 201 到 300 之前(包含父發行項變更)。 中斷可能是因為網路連線中斷、查詢逾時等等。 合併代理程式 可以認可沒有父數據列的子發行項數據列,因為伺服器端外鍵條件約束標示為 NOT FOR REPLICATION,因此會「暫停」條件約束的檢查。
- 在 publisher-republisher 合併代理程式 重新開始處理之前,重新發布訂閱者 合併代理程式 開始合併會話。 它會開始從重新發佈者下載變更的程式。
- 當重新發行者-訂閱者 合併代理程式 處理層代 110 時(子發行項 INSERTs),它會評估子發行項與父發行項之間存在的聯結篩選。 因為父發行項變更尚未抵達重新發行者,因此 合併代理程式 會判斷這些子 INSERT 不會「限定」聯結篩選條件。 合併代理程式 會下載代表層代 110 的MSmerge_genhistory數據列,但該層代中沒有任何變更。 此 合併代理程式 成功完成其會話。
- 發行者與重新發行者之間的後續 合併代理程式 會成功處理包含父發行項 INSERT(層代 201 到 300 層)的世代批次,並在重新發行者端認可這些變更。
- 最後,重新發行者與訂閱者之間的後續 合併代理程式 會話會考慮層代 250,並將父發行項 INSERT 下載至訂閱者。 不過,因為訂閱者也知道層代 110 (子發行項的世代),因此 合併代理程式 不會重新評估子發行項的數據分割。
這會導致重新發行者端有子數據列出現在訂閱者 orphaned
端的正確父發行項數據列。