当复制有延迟时,我们可以使用复制监视器来查看各订阅的未分发命令书和预估所需时间,如下图:
但是当分发和订阅数比较多的时候,依次查看比较费时,我们可以使用sys.sp_replmonitorsubscriptionpendingcmds来查看,但是该命令需要输入多个参数,也比较累人,后从菠萝兄哪找寻得一个脚本,对该命令进行了一次封装:
--在分发服务器执行 USE distribution SELECT 'EXEC distribution.sys.sp_replmonitorsubscriptionpendingcmds @publisher = N'''+ a.publisher + ''', @publisher_db = N''' + a.publisher_db+ ''', @publication = N''' + a.publication + ''', @subscriber = N'''+ c.name + ''', @subscriber_db = N''' + b.subscriber_db+ ''', @subscription_type =' + CAST(b.subscription_type AS VARCHAR) FROM dbo.MSreplication_monitordata a ( NOLOCK )JOIN ( SELECT publication_id ,subscriber_id ,subscriber_db ,subscription_typeFROM MSsubscriptions (NOLOCK)GROUP BY publication_id ,subscriber_id ,subscriber_db ,subscription_type) b ON a.publication_id = b.publication_idJOIN sys.servers c ( NOLOCK ) ON b.subscriber_id = c.server_id WHERE a.agent_type = 1
执行该脚本,可以生成相应命令,再依次执行命令可以获取我们想要的结果。
为方便查看,我在菠萝的脚本上做了改进,以便可以更方便查看:
--查看为传递到订阅的命令和预估时间 --在分发服务器执行 IF(OBJECT_ID('tempdb..#tmpSubscribers') IS NOT NULL) BEGIN DROP TABLE #tmpSubscribers END GO --IF(OBJECT_ID('tempdb..#tmpPendingResult') IS NOT NULL) --BEGIN --DROP TABLE #tmpPendingResult --END--GO --IF(OBJECT_ID('tempdb..#tmpSinglePendingResult') IS NOT NULL) --BEGIN --DROP TABLE #tmpSinglePendingResult --END GO USE distribution GO SELECT a.publisher ,a.publisher_db ,a.publication ,c.name as subscriber ,b.subscriber_db as subscriber_db ,CAST(b.subscription_type AS VARCHAR) as subscription_type ,'EXEC distribution.sys.sp_replmonitorsubscriptionpendingcmds @publisher = N'''+ a.publisher + ''', @publisher_db = N''' + a.publisher_db+ ''', @publication = N''' + a.publication + ''', @subscriber = N'''+ c.name + ''', @subscriber_db = N''' + b.subscriber_db+ ''', @subscription_type =' + CAST(b.subscription_type AS VARCHAR) AS ScriptTxt INTO #tmpSubscribers FROM dbo.MSreplication_monitordata a ( NOLOCK )JOIN ( SELECT publication_id ,subscriber_id ,subscriber_db ,subscription_typeFROM MSsubscriptions (NOLOCK)GROUP BY publication_id ,subscriber_id ,subscriber_db ,subscription_type) b ON a.publication_id = b.publication_idJOIN sys.servers c ( NOLOCK ) ON b.subscriber_id = c.server_id WHERE a.agent_type = 1 --==================================================== --CREATE TABLE #tmpPendingResult --( --publisher NVARCHAR(200) --,publisher_db NVARCHAR(200) --,publication NVARCHAR(200) --,subscriber NVARCHAR(200) --,subscriber_db NVARCHAR(200) --,subscription_type NVARCHAR(200) --,pendingcmdcount BIGINT --,estimatedprocesstime BIGINT --)--CREATE TABLE #tmpSinglePendingResult --( --pendingcmdcount BIGINT --,estimatedprocesstime BIGINT --)--================================================== --使用游标遍历 DECLARE @publisher NVARCHAR(200);; DECLARE @publisher_db NVARCHAR(200); DECLARE @publication NVARCHAR(200);DECLARE @subscriber NVARCHAR(200);; DECLARE @subscriber_db NVARCHAR(200); DECLARE @subscription_type NVARCHAR(200); DECLARE @ScriptTxt NVARCHAR(MAX);DECLARE MyCursor CURSOR FOR SELECT publisher ,publisher_db ,publication ,subscriber ,subscriber_db ,subscription_type ,ScriptTxt FROM #tmpSubscribers;OPEN MyCursorFETCH NEXT FROM MyCursor INTO @publisher ,@publisher_db ,@publication ,@subscriber ,@subscriber_db ,@subscription_type ,@ScriptTxt;WHILE @@FETCH_STATUS = 0 BEGIN SELECT @publisher AS publisher ,@publisher_db AS publisher_db ,@publication AS publication ,@subscriber AS subscriber ,@subscriber_db AS subscriber_db ,@subscription_type AS subscription_type ,@ScriptTxt;EXEC(@ScriptTxt)FETCH NEXT FROM MyCursor INTO @publisher ,@publisher_db ,@publication ,@subscriber ,@subscriber_db ,@subscription_type ,@ScriptTxt;ENDCLOSE MyCursor DEALLOCATE MyCursor
由于使用sp_replmonitorsubscriptionpendingcmds,无法将存储过程的结果插入到一个临时表中查看,因此想到参考其存储过程,编写一个类似脚本,于是有了下面脚本:
USE distribution go IF ( OBJECT_ID('dbo.sp_replmonitorsubscriptionpendingcmds_EX ') IS NOT NULL ) BEGINDROP PROCEDURE dbo.sp_replmonitorsubscriptionpendingcmds_EX END GO CREATE PROCEDURE dbo.sp_replmonitorsubscriptionpendingcmds_EX AS BEGINSET nocount ONCREATE TABLE #tmpPendingResult(publisher NVARCHAR(200) ,publisher_db NVARCHAR(200) ,publication NVARCHAR(200) ,subscriber NVARCHAR(200) ,subscriber_db NVARCHAR(200) ,subscription_type NVARCHAR(200) ,pendingcmdcount BIGINT ,estimatedprocesstime BIGINT)--查找所有订阅SELECT a.publisher ,a.publisher_db ,a.publication ,c.name AS subscriber ,b.subscriber_db AS subscriber_db ,CAST(b.subscription_type AS VARCHAR) AS subscription_typeINTO #tmpSubscribersFROM dbo.MSreplication_monitordata a ( NOLOCK )JOIN ( SELECT publication_id ,subscriber_id ,subscriber_db ,subscription_typeFROM MSsubscriptions (NOLOCK)GROUP BY publication_id ,subscriber_id ,subscriber_db ,subscription_type) b ON a.publication_id = b.publication_idJOIN sys.servers c ( NOLOCK ) ON b.subscriber_id = c.server_idWHERE a.agent_type = 1DECLARE @count INTSELECT @count = COUNT(1)FROM #tmpSubscribersPRINT 'Subscriber Counter:' + CAST(@count AS VARCHAR(200));DECLARE @publisher NVARCHAR(200);;DECLARE @publisher_db NVARCHAR(200);DECLARE @publication NVARCHAR(200);DECLARE @subscriber NVARCHAR(200);;DECLARE @subscriber_db NVARCHAR(200);DECLARE @subscription_type NVARCHAR(200);DECLARE MyCursor CURSORFORSELECT publisher ,publisher_db ,publication ,subscriber ,subscriber_db ,subscription_typeFROM #tmpSubscribers;OPEN MyCursorFETCH NEXT FROM MyCursor INTO @publisher, @publisher_db, @publication, @subscriber, @subscriber_db,@subscription_type;DECLARE @Error NVARCHAR(MAX)WHILE @@FETCH_STATUS = 0 BEGINSELECT @Error = '@publisher=' + @publisher+ ';@publisher_db=' + @publisher_db + ';@publication='+ @publication + ';@subscriber=' + @subscriber+ ';@subscriber_db' + @subscriber_dbPRINT '开始:' + @Error;DECLARE @retcode INT ,@agent_id INT ,@publisher_id INT ,@subscriber_id INT ,@lastrunts TIMESTAMP ,@avg_rate FLOAT ,@xact_seqno VARBINARY(16) ,@inactive INT = 1 ,@virtual INT = -1-- -- PAL security check done inside sp_MSget_repl_commands-- security: Has to be executed from distribution database-- -- if sys.fn_MSrepl_isdistdb (db_name()) != 1-- begin-- --raiserror (21482, 16, -1, 'sp_replmonitorsubscriptionpendingcmds', 'distribution')-- --return 1--SELECT @Error='@publisher='+@publisher+';@publisher_db='+@publisher_db--+';@publication='+@publication+';@subscriber='+@subscriber+';@subscriber_db'+@subscriber_db--PRINT @Error--CONTINUE;-- end-- -- validate @subscription_type-- IF ( @subscription_type NOT IN ( 0, 1 ) ) BEGIN--raiserror(14200, 16, 3, '@subscription_type')--return 1PRINT 'ERROR IN subscription_type'CONTINUE;END-- -- get the server ids for publisher and subscriber-- SELECT @publisher_id = server_idFROM sys.serversWHERE UPPER(name) = UPPER(@publisher)IF ( @publisher_id IS NULL ) BEGIN--raiserror(21618, 16, -1, @publisher)--return 1PRINT 'ERROR IN publisher_id'CONTINUE;ENDSELECT @subscriber_id = server_idFROM sys.serversWHERE UPPER(name) = UPPER(@subscriber)IF ( @subscriber_id IS NULL ) BEGIN--raiserror(20032, 16, -1, @subscriber, @publisher)--return 1PRINT 'ERROR IN subscriber_id'CONTINUE;END-- -- get the agent id-- SELECT @agent_id = idFROM dbo.MSdistribution_agentsWHERE publisher_id = @publisher_idAND publisher_db = @publisher_dbAND publication IN ( @publication, 'ALL' )AND subscriber_id = @subscriber_idAND subscriber_db = @subscriber_dbAND subscription_type = @subscription_typeIF ( @agent_id IS NULL ) BEGIN--raiserror(14055, 16, -1)--return (1)PRINT 'ERROR IN agent_id'CONTINUE;END;-- -- Compute timestamp for latest run-- WITH dist_sessions ( start_time, runstatus, timestamp )AS ( SELECT start_time ,MAX(runstatus) ,MAX(timestamp)FROM dbo.MSdistribution_historyWHERE agent_id = @agent_idAND runstatus IN ( 2, 3, 4 )GROUP BY start_time)SELECT @lastrunts = MAX(timestamp)FROM dist_sessions;IF ( @lastrunts IS NULL ) BEGIN-- -- Distribution agent has not run successfully even once-- and virtual subscription of immediate sync publication is inactive (snapshot has not run), no point of returning any counts-- see SQLBU#320752, orig fix SD#881433, and regression bug VSTS# 140179 before you attempt to fix it differently :)IF EXISTS ( SELECT *FROM dbo.MSpublications pJOIN dbo.MSsubscriptions s ON p.publication_id = s.publication_idWHERE p.publisher_id = @publisher_idAND p.publisher_db = @publisher_dbAND p.publication = @publicationAND p.immediate_sync = 1AND s.status = @inactiveAND s.subscriber_id = @virtual ) BEGIN-- select 'pendingcmdcount' = 0, N'estimatedprocesstime' = 0--return 0INSERT INTO #tmpPendingResult( publisher ,publisher_db ,publication ,subscriber ,subscriber_db ,subscription_type ,pendingcmdcount ,estimatedprocesstime)SELECT @publisher ,@publisher_db ,@publication ,@subscriber ,@subscriber_db ,@subscription_type ,0 ,0END-- -- Grab the max timestamp-- SELECT @lastrunts = MAX(timestamp)FROM dbo.MSdistribution_historyWHERE agent_id = @agent_idEND-- -- get delivery rate for the latest completed run-- get the latest sequence number-- SELECT @xact_seqno = xact_seqno ,@avg_rate = delivery_rateFROM dbo.MSdistribution_historyWHERE agent_id = @agent_idAND timestamp = @lastrunts-- -- if no rows are selected in last query-- explicitly initialize these variables-- SELECT @xact_seqno = ISNULL(@xact_seqno, 0x0) ,@avg_rate = ISNULL(@avg_rate, 0.0)-- -- if we do not have completed run-- get the average for the agent in all runs-- IF ( @avg_rate = 0.0 ) BEGINSELECT @avg_rate = ISNULL(AVG(delivery_rate), 0.0)FROM dbo.MSdistribution_historyWHERE agent_id = @agent_idEND-- -- get the count of undelivered commands-- PAL check done inside-- DECLARE @countab TABLE ( pendingcmdcount INT )INSERT INTO @countab( pendingcmdcount)EXEC @retcode = sys.sp_MSget_repl_commands @agent_id = @agent_id,@last_xact_seqno = @xact_seqno, @get_count = 2,@compatibility_level = 9000000IF ( @retcode != 0OR @@error != 0)--return 1CONTINUE;-- -- compute the time to process-- return the resultset-- INSERT INTO #tmpPendingResult( publisher ,publisher_db ,publication ,subscriber ,subscriber_db ,subscription_type ,pendingcmdcount ,estimatedprocesstime)SELECT @publisher ,@publisher_db ,@publication ,@subscriber ,@subscriber_db ,@subscription_type ,pendingcmdcount ,CASE WHEN ( @avg_rate != 0.0 )THEN CAST(( CAST(pendingcmdcount AS FLOAT)/ @avg_rate ) AS INT)ELSE pendingcmdcountENDFROM @countab-- -- all done-- --CONTINUE;FETCH NEXT FROM MyCursor INTO @publisher, @publisher_db, @publication, @subscriber, @subscriber_db,@subscription_type;ENDCLOSE MyCursorDEALLOCATE MyCursorSELECT *FROM #tmpPendingResultEND GO --========================================================= --测试 EXEC dbo.sp_replmonitorsubscriptionpendingcmds_EX
上面相对使用起来更方便些。哈哈
--============================================================================================
来个妹子给大家降降温