首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

SQL Server 交易式複寫深度解析:如何跳過卡住的大型事務

     編輯:關於SqlServer

在 SQL Server 交易式複寫環境中,資料同步延遲是常見挑戰。當發行端執行大量資料更新(如 UPDATE ta SET col = ? WHERE ?)時,該交易會在訂閱端拆解為逐行命令應用,導致散發代理程式長時間佔用資源,嚴重拖慢後續同步。若無法等待其完成,必須採取干預措施跳過該交易,讓複寫恢復正常流程。

核心原理:LSN 與散發代理雙執行緒機制

發行資料庫的文章更新會產生交易記錄,記錄讀取器將其寫入散發資料庫的 msrepl_transactions 與 msrepl_commands 表。每筆交易擁有唯一 xact_seqno,對應發行端的 LSN(日誌序號),序號越大代表生成時間越晚。

散發代理包含 Reader 與 Writer 兩個子執行緒:

  • Reader:透過 sp_MSget_repl_commands 從散發資料庫讀取命令。
  • Writer:將讀取的命令寫入訂閱資料庫。

關鍵參數 @last_xact_seqno 代表上次成功傳遞至訂閱端的 LSN。Reader 從訂閱端 MSreplication_subscriptions 表的 transaction_timestamp 取得該值,並讀取大於此 LSN 的資料;Writer 寫入後更新該欄位,形成循環。

實戰演示:手動更新 LSN 跳過大型交易

環境架構

  • 發行者:SQL108W2K8R21
  • 散發者:SQL108W2K8R22
  • 訂閱者:SQL108W2K8R23

發行集包含 ta、tb、tc 三個文章,ta 含 1821 萬筆資料

問題重現:11:00 執行 UPDATE ta SET c = -11,隨後陸續對 ta、tb、tc 插入資料。啟動複寫監視器發現嚴重延遲,散發代理持續傳遞大量更新命令。

複寫監視器顯示延遲 代理程式詳細狀態

步驟 1:取得訂閱端目前 LSN

DECLARE @publisher sysname, @publicationDB sysname, @publication sysname;
SET @publisher = 'SQL108W2K8R22';
SET @publicationDB = 'pubdb';
SET @publication = 'pubdbtest2';
SELECT transaction_timestamp
FROM MSreplication_subscriptions
WHERE publisher = @publisher
  AND publisher_db = @publicationDB
  AND publication = @publication;

假設取得 0x0000014900004E9A0004000000000000。

步驟 2:在散發資料庫找出大型交易之後的下一筆 LSN

DECLARE @publisher sysname, @publicationDB sysname, @publication sysname, @transaction_timestamp varbinary(16);
SET @publisher = 'SQL108W2K8R21';
SET @publicationDB = 'publicationdb2';
SET @publication = 'pubtest';
SET @transaction_timestamp = 0x0000014900004E9A0004000000000000;

SELECT TOP 1 xact_seqno
FROM MSrepl_commands WITH (NOLOCK)
WHERE xact_seqno > @transaction_timestamp
  AND article_id IN (
    SELECT a.article_id
    FROM MSarticles a
    INNER JOIN MSpublications p ON a.publication_id = p.publication_id
                                 AND a.publisher_id = p.publisher_id
                                 AND a.publisher_db = p.publisher_db
    INNER JOIN sys.servers s ON s.server_id = p.publisher_id
    WHERE p.publication = @publication
      AND p.publisher_db = @publicationDB
      AND s.name = @publisher
  )
  AND publisher_database_id = (
    SELECT pd.id
    FROM MSpublisher_databases pd
    INNER JOIN MSpublications p ON pd.publisher_id = p.publisher_id
    INNER JOIN sys.servers s ON pd.publisher_id = s.server_id
                              AND pd.publisher_db = p.publisher_db
    WHERE s.name = @publisher
      AND p.publication = @publication
      AND pd.publisher_db = @publicationDB
  )
ORDER BY xact_seqno;

假設取得 0x0000018C000001000171,即為要跳過至的目標 LSN。

步驟 3:更新訂閱端 LSN 完成跳過

DECLARE @publisher sysname, @publicationDB sysname, @publication sysname, @transaction_timestamp varbinary(16);
SET @publisher = 'SQL108W2K8R22';
SET @publicationDB = 'pubdb';
SET @publication = 'pubdbtest2';
SET @transaction_timestamp = 0x0000018C000001000171;

UPDATE MSreplication_subscriptions
SET transaction_timestamp = @transaction_timestamp
WHERE publisher = @publisher
  AND publisher_db = @publicationDB
  AND publication = @publication;

執行完成後重新啟動散發代理作業,即可發現大型交易已被跳過,ta 表在訂閱端不會套用該更新,後續交易陸續同步,延遲消失。

注意:此操作會導致訂閱端資料與發行端暫時不一致,需事後透過資料比對或重新初始化修復。僅建議在無法容忍延遲且確認該交易可接受遺失時使用。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved