使用同義詞和insert..from..語句,解決訂閱庫數據丟失的問題 ...
最近給客戶做了基於SQLServer的發佈訂閱的“讀寫分離”功能,但是某些表數據很大,經常發生某幾條數據丟失的問題,導致訂閱無法繼續進行。但是每次發現問題重新做一次發佈訂閱又非常消耗時間,所以還得根據“複製監視器”的提示,找到丟失的數據,手工處理。
定位缺失數據
首先,找到出問題的同步語句,在發佈伺服器的“複製監視器”上事務訂閱的詳細信息裡面,找到出錯的信息
嘗試的命令: if @@trancount > 0 rollback tran (事務序列號: 0x0000992600000D09007F00000000,命令 ID: 19) 錯誤消息: 應用複製的命令時在訂閱伺服器上找不到該行。 (源: MSSQLServer,錯誤號: 20598) 獲取幫助: http://help/20598 應用複製的命令時在訂閱伺服器上找不到該行。 (源: MSSQLServer,錯誤號: 20598)
然後在分發伺服器上執行下麵的SQL語句,
use distribution go sp_browsereplcmds '0x0000992600000D09007F00000000' ,'0x0000992600000D09007F00000000' go
根據命令ID(如上面的ID:19),找到具體的同步命令(Command列),類似於這樣的:
{CALL [dbo].[sp_MSdel_dboT_FFTODO] ('697e7cacf5354a36be1ae4cf50dcdaa6')}
這裡是 訂閱庫上的 sp_MSdel_dboT_FFTODO 存儲過程,查看存儲過程定義知道參數是ID的值,這裡說找不到要刪除的數據,那麼我們在訂閱庫裡面模擬增加這個ID的記錄即可。添加數據,
補錄數據
網上提供的解決方案是用一個工具生成差異的SQL數據然後給訂閱庫執行,但看了下覺得不是很方便,想起來SqlServer還提供一個 insert...from....語句,那麼是否可以直接從發佈資料庫查詢數據然後插入給訂閱資料庫呢?
可以使用同義詞從發佈庫查詢過來插入到本地訂閱庫,請看下麵具體過程:
先在訂閱庫上建立一個同義詞,比如下麵為表 Biz_Customer 建立一個同義詞 Biz_Customer_Master,建立的時候,要求指定同義詞所在的伺服器名稱,資料庫名稱,架構,表名稱等信息。
但是此時同義詞還不能直接使用,還需要建立“鏈接伺服器”,具體過程如下:
EXEC sp_addlinkedserver @server='192.168.7.4',--被訪問的伺服器別名(習慣上直接使用目標伺服器IP,或取個別名如:JOY) @srvproduct='', @provider='SQLOLEDB', @datasrc='192.168.7.4' --要訪問的伺服器 go EXEC sp_addlinkedsrvlogin '192.168.7.4', --被訪問的伺服器別名(如果上面sp_addlinkedserver中使用別名JOY,則這裡也是JOY) 'false', NULL, 'sa', --帳號 '1234567890' --密碼 go select * from sys.servers;
然後使用下麵的SQL語句插入數據:
insert into [Biz_Customer] select * from Biz_Customer_Master where id='7B210173-7382-43EB-BC5E-0000C3BA564A'
查詢報錯,某個列的數據類型錯誤,打開表一看,原來是 發佈庫上的表的欄位順序跟訂閱庫上不一樣,因為當初做訂閱的時候,為瞭解決Timestamp 問題,將訂閱庫的Timestamp欄位修改成了binary(8)類型,故訂閱庫上表的欄位順序改變了。
此時,只需要在insert 和 select 語句上,指定相同順序的列就可以了。那麼如何獲取表所有的列名稱?
很簡單,直接選擇某個表,新建查詢,生成的SQL語句就包含表所有的欄位了。
最後正確的語句如下:
insert into [Biz_Customer]([Id] ,[CustomerId] ,[Code] ,[Name] ,[BusinessId] ,[CreatedOn] ,[CreatedById] ,[ModifiedOn] ,[ModifiedById] ,[AppraiseTableType] ,[Timestamp] ) SELECT [Id] ,[CustomerId] ,[Code] ,[Name] ,[BusinessId] ,[CreatedOn] ,[CreatedById] ,[ModifiedOn] ,[ModifiedById] ,[AppraiseTableType] ,[Timestamp] FROM dbo.Biz_Customer_Master where id='7B210173-7382-43EB-BC5E-0000C3BA564A';
經過這樣的方式,很方便的把發佈庫的數據就補充到訂閱庫上了,之後,資料庫的發佈訂閱錯誤就解決了。