首页 > 代码库 > Replication--查看未分发命令和预估所需时间

Replication--查看未分发命令和预估所需时间

当复制有延迟时,我们可以使用复制监视器来查看各订阅的未分发命令书和预估所需时间,如下图:

但是当分发和订阅数比较多的时候,依次查看比较费时,我们可以使用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_type               FROM     MSsubscriptions (NOLOCK)               GROUP BY publication_id ,                        subscriber_id ,                        subscriber_db ,                        subscription_type             ) b ON a.publication_id = b.publication_id        JOIN sys.servers c ( NOLOCK ) ON b.subscriber_id = c.server_idWHERE   a.agent_type = 1

执行该脚本,可以生成相应命令,再依次执行命令可以获取我们想要的结果。

为方便查看,我在菠萝的脚本上做了改进,以便可以更方便查看:

--查看为传递到订阅的命令和预估时间--在分发服务器执行 IF(OBJECT_ID(tempdb..#tmpSubscribers) IS NOT NULL)BEGINDROP TABLE #tmpSubscribersENDGO--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--ENDGOUSE distribution GOSELECT  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 ScriptTxtINTO #tmpSubscribersFROM    dbo.MSreplication_monitordata a ( NOLOCK )        JOIN ( SELECT   publication_id ,                        subscriber_id ,                        subscriber_db ,                        subscription_type               FROM     MSsubscriptions (NOLOCK)               GROUP BY publication_id ,                        subscriber_id ,                        subscriber_db ,                        subscription_type             ) b ON a.publication_id = b.publication_id        JOIN sys.servers c ( NOLOCK ) ON b.subscriber_id = c.server_idWHERE   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 FORSELECT publisher,publisher_db ,publication,subscriber,subscriber_db,subscription_type,ScriptTxtFROM #tmpSubscribers;OPEN MyCursorFETCH NEXT FROM MyCursor INTO @publisher,@publisher_db ,@publication,@subscriber,@subscriber_db,@subscription_type,@ScriptTxt;WHILE @@FETCH_STATUS = 0BEGINSELECT @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 MyCursorDEALLOCATE MyCursor

由于使用sp_replmonitorsubscriptionpendingcmds,无法将存储过程的结果插入到一个临时表中查看,因此想到参考其存储过程,编写一个类似脚本,于是有了下面脚本:

USE distributiongoIF ( OBJECT_ID(dbo.sp_replmonitorsubscriptionpendingcmds_EX ) IS NOT NULL )     BEGIN        DROP PROCEDURE dbo.sp_replmonitorsubscriptionpendingcmds_EX     ENDGOCREATE PROCEDURE dbo.sp_replmonitorsubscriptionpendingcmds_EXAS     BEGIN        SET nocount ON        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            )--查找所有订阅        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        INTO    #tmpSubscribers        FROM    dbo.MSreplication_monitordata a ( NOLOCK )                JOIN ( SELECT   publication_id ,                                subscriber_id ,                                subscriber_db ,                                subscription_type                       FROM     MSsubscriptions (NOLOCK)                       GROUP BY publication_id ,                                subscriber_id ,                                subscriber_db ,                                subscription_type                     ) b ON a.publication_id = b.publication_id                JOIN sys.servers c ( NOLOCK ) ON b.subscriber_id = c.server_id        WHERE   a.agent_type = 1        DECLARE @count INT        SELECT  @count = COUNT(1)        FROM    #tmpSubscribers        PRINT 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 CURSOR        FOR            SELECT  publisher ,                    publisher_db ,                    publication ,                    subscriber ,                    subscriber_db ,                    subscription_type            FROM    #tmpSubscribers;        OPEN MyCursor        FETCH NEXT FROM MyCursor INTO @publisher, @publisher_db, @publication, @subscriber, @subscriber_db,            @subscription_type;        DECLARE @Error NVARCHAR(MAX)        WHILE @@FETCH_STATUS = 0             BEGIN                SELECT  @Error = @publisher= + @publisher                        + ;@publisher_db= + @publisher_db + ;@publication=                        + @publication + ;@subscriber= + @subscriber                        + ;@subscriber_db + @subscriber_db                        PRINT 开始: + @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 1                                PRINT ERROR IN subscription_type                        CONTINUE;                    END    --    -- get the server ids for publisher and subscriber    --                SELECT  @publisher_id = server_id                FROM    sys.servers                WHERE   UPPER(name) = UPPER(@publisher)                IF ( @publisher_id IS NULL )                     BEGIN        --raiserror(21618, 16, -1, @publisher)        --return 1                                PRINT ERROR IN publisher_id                        CONTINUE;                    END                SELECT  @subscriber_id = server_id                FROM    sys.servers                WHERE   UPPER(name) = UPPER(@subscriber)                IF ( @subscriber_id IS NULL )                     BEGIN        --raiserror(20032, 16, -1, @subscriber, @publisher)        --return 1                                PRINT ERROR IN subscriber_id                        CONTINUE;                    END    --    -- get the agent id    --                SELECT  @agent_id = id                FROM    dbo.MSdistribution_agents                WHERE   publisher_id = @publisher_id                        AND publisher_db = @publisher_db                        AND publication IN ( @publication, ALL )                        AND subscriber_id = @subscriber_id                        AND subscriber_db = @subscriber_db                        AND subscription_type = @subscription_type                IF ( @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_history                               WHERE    agent_id = @agent_id                                        AND 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 p                                            JOIN dbo.MSsubscriptions s ON p.publication_id = s.publication_id                                    WHERE   p.publisher_id = @publisher_id                                            AND p.publisher_db = @publisher_db                                            AND p.publication = @publication                                            AND p.immediate_sync = 1                                            AND s.status = @inactive                                            AND s.subscriber_id = @virtual )                             BEGIN         --   select ‘pendingcmdcount‘ = 0, N‘estimatedprocesstime‘ = 0            --return 0                                INSERT  INTO #tmpPendingResult                                        ( publisher ,                                          publisher_db ,                                          publication ,                                          subscriber ,                                          subscriber_db ,                                          subscription_type ,                                          pendingcmdcount ,                                          estimatedprocesstime                                        )                                        SELECT  @publisher ,                                                @publisher_db ,                                                @publication ,                                                @subscriber ,                                                @subscriber_db ,                                                @subscription_type ,                                                0 ,                                                0                            END        --        -- Grab the max timestamp        --                        SELECT  @lastrunts = MAX(timestamp)                        FROM    dbo.MSdistribution_history                        WHERE   agent_id = @agent_id                    END    --    -- get delivery rate for the latest completed run    -- get the latest sequence number    --                SELECT  @xact_seqno = xact_seqno ,                        @avg_rate = delivery_rate                FROM    dbo.MSdistribution_history                WHERE   agent_id = @agent_id                        AND 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 )                     BEGIN                        SELECT  @avg_rate = ISNULL(AVG(delivery_rate), 0.0)                        FROM    dbo.MSdistribution_history                        WHERE   agent_id = @agent_id                    END    --    -- 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 = 9000000                IF ( @retcode != 0                     OR @@error != 0                   )        --return 1                    CONTINUE;    --    -- 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 pendingcmdcount                                END                        FROM    @countab    --    -- all done    --    --CONTINUE;                FETCH NEXT FROM MyCursor INTO @publisher, @publisher_db, @publication, @subscriber, @subscriber_db,                    @subscription_type;            END        CLOSE MyCursor        DEALLOCATE MyCursor        SELECT  *        FROM    #tmpPendingResult    ENDGO--=========================================================--测试EXEC dbo.sp_replmonitorsubscriptionpendingcmds_EX 

上面相对使用起来更方便些。哈哈

--============================================================================================

来个妹子给大家降降温