最近遇到“應用復制的命令時在訂閱服務器上找不到該行”問題,報錯如下:
官方給出的建議是重新同步和初始化訂閱,當然,這是一種選擇,但是對於動輒上百G的生產庫,這種方法會消耗大量的資源和時間。可以通過定位出錯數據,選擇跳過,等從庫追平主庫后,修復錯誤數據方式,達到最終主從數據一致。
解決思路
1. 找到分發任務的事務序列號
獲取當前出錯的事務序列號有如下方法:
- 如果是復制分發停止了,那么在錯誤信息中會顯示事務序列號。上圖中是‘0x000311CC00013A7300010000000’
- 如果復制錯誤信息在顯示窗口中被覆蓋,比如選擇了跳過錯誤(經過試驗,發現跳過錯誤后,事務號會顯示0x0000000000000000000000000000,所以最好不要跳過),或者其他錯誤覆蓋了該錯誤,可以在分發服務器上執行 :
sp_helpsubscriptionerrors [ @publisher = ]'publisher' , [ @publisher_db = ]'publisher_db' , [ @publication = ]'publication' , [ @subscriber = ]'subscriber' , [ @subscriber_db = ]'subscriber_db'
參數對應值可以通過在分發服務器查詢獲取:
獲取publisher和subscriber
select * from MSsubscriber_info
獲取publisher_db和publication
select * from MSpublications
在訂閱服務器上執行,獲取事務序列號
sp_setsubscriptionxactseqno [ @publisher= ]'publisher', [ @publisher_db= ]'publisher_db', [ @publication= ]'publication', [ @xact_seqno= ] xact_seqno
示例:
- 直接查詢訂閱服務器目標庫上相關表,字段transaction_timestamp就是序列號
SELECT * FROM dbo.MSreplication_subscriptions
2. 查看出錯命令
獲取事務序列號之后,查看事務號對應的具體命令:
sp_browsereplcmds [ [ @xact_seqno_start = ] 'xact_seqno_start' ] [ , [ @xact_seqno_end = ] 'xact_seqno_end' ] [ , [ @originator_id = ] 'originator_id' ] [ , [ @publisher_database_id = ] 'publisher_database_id' ] [ , [ @article_id = ] 'article_id' ] [ , [ @command_id= ] command_id ] [ , [ @agent_id = ] agent_id ] [ , [ @compatibility_level = ] compatibility_level ]
前兩個參數是開始事務號和結束事務號,建議一定要輸入publisher_database_id這個參數。該存儲過程實際上查詢的是MSrepl_commands表,該表的復合索引前綴是publisher_database_id該字段,對於大數據量的分法庫,沒用到索引的查詢所消耗的時間可想而知。
command 默認的命名規則是sp_MS+operation+_schemaName+tableName
通過示例知道該操作表示對T_CarPakingRecord表進行update操作,最后的表示的是主鍵。
3. 補救措施
根據上面分析的命令結果,將完整數據插入到從庫中(這里是補救缺失行錯誤,如果是插入重復則直接刪除即可)
如果認為數據一致性不重要,則可以直接跳過,不推薦這樣。跳過錯誤的命令:
sp_setsubscriptionxactseqno [ @publisher = ] '發布服務器主機名' , [ @publisher_db = ] '發布數據庫' , [ @publication = ] '發布名稱' , [ @xact_seqno = ] 跳過的事務號