/*============================================================================= User guide --------------------------------------------------- 01. Create Table [Replication_queue_history] 02. Create Indexes [NCIX_?] 03. Create stored procedure [Get_replication_counters] 04. Create Job [DR92280 - Monitoring SQL Server Replication] Usage context ------------------------------------------ To collect performance status for all publication's subscriptions in the server Parameters ------------------------------------------ Creation : 27.10.21 / RTC Modification : 17.03.2022 - FLA : Change DBA mail 22.04.2022 - FLA : Correct SP location in job =============================================================================*/ /***************************************************************/ /****** Create Table [Replication_queue_history] *******/ /***************************************************************/ USE [HCITools] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[mon].[Replication_queue_history]') AND type in (N'U')) BEGIN CREATE TABLE mon.Replication_queue_history( Replication_queue_history_Id INT IDENTITY(1,1) NOT NULL, RQH_subscriber_db VARCHAR(50) NOT NULL, RQH_records_in_queue NUMERIC(18, 0) NULL, RQH_catch_up_time NUMERIC(18, 0) NULL, RQH_log_date DATETIME NOT NULL CONSTRAINT PK_EPR_Replication_queue_history PRIMARY KEY CLUSTERED ( RQH_subscriber_db ASC, RQH_log_date DESC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] END GO /***************************************************************/ /****** Create Procedure [Get_replication_counters] *******/ /***************************************************************/ IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[mon_Get_Replication_Counters]') AND type in (N'P', N'PC')) DROP PROCEDURE [dbo].[mon_Get_Replication_Counters] GO CREATE PROCEDURE [dbo].[mon_Get_Replication_Counters] @in_debug INT = NULL AS /*============================================================================= Explication du traitement realise par la SP ------------------------------------------- To collect performance counters in SQL Server Replication Contexte d'utilisation ---------------------- Job : DR92280 - Monitoring SQL Server Replication Parametres ---------- @in_debug Creation : 27.10.2021 / RTC Modifications : =============================================================================*/ DECLARE @cmd NVARCHAR(max) DECLARE @publisher SYSNAME, @publisher_db SYSNAME, @publication SYSNAME, @pubtype INT DECLARE @subscriber SYSNAME, @subscriber_db SYSNAME, @subtype INT DECLARE @cmdcount INT, @processtime INT DECLARE @ParmDefinition NVARCHAR(500) DECLARE @JobName SYSNAME DECLARE @minutes INT, @threshold INT, @maxCommands INT, @mail CHAR(1) = 'N' SET @minutes = 60 --> Define how many minutes latency before you would like to be notified SET @maxCommands = 80000 ---> change this to represent the max number of outstanding commands to be proceduresed before notification SET @threshold = @minutes * 60 /* Drop all temp tables */ IF OBJECT_ID(N'tempdb..#PublisherInfo') is not null drop table #PublisherInfo if exists (SELECT * FROM [TempDB].sys.objects o WITH (NOLOCK) WHERE o.name = '##PublicationInfo' AND o.type IN (N'U')) Drop table ##PublicationInfo if exists (SELECT * FROM [TempDB].sys.objects o WITH (NOLOCK) WHERE o.name = '##SubscriptionInfo' AND o.type IN (N'U')) Drop table ##SubscriptionInfo SELECT * INTO #PublisherInfo FROM OPENROWSET('SQLOLEDB', 'SERVER=(LOCAL);TRUSTED_CONNECTION=YES;', 'SET FMTONLY OFF EXEC distribution.dbo.sp_replmonitorhelppublisher WITH RESULT SETS ((publisher sysname, Distribution_db sysname, status int, warning int, publication_count int, returnstamp bigint))') -- select * from #PublisherInfo SELECT @publisher = publisher FROM #PublisherInfo SET @cmd = 'SELECT * INTO ##PublicationInfo FROM OPENROWSET(''SQLOLEDB'',''SERVER=(LOCAL);TRUSTED_CONNECTION=YES'' ,''SET FMTONLY OFF EXEC distribution.dbo.sp_replmonitorhelppublication @publisher= ''''' + @publisher + ''''' with result sets ((publisher_db sysname, publication sysname, publication_id int, publication_type int, status int, warning int, worst_latency int, best_latency int, average_latency int, last_distsync datetime, retention int, latencythreshold int, expirationthreshold int, agentnotrunningthreshold int, subscriptioncount int, runningdistagentcount int, snapshot_agentname sysname, logreader_agentname sysname, qreader_agentname sysname, worst_runspeedPerf int, best_runspeedPerf int, average_runspeedPerf int, retention_period_unit int, publisher sysname))'')' --select @cmd EXEC sp_executesql @cmd select * FROM ##PublicationInfo SELECT @publisher_db = publisher_db, @publication = publication, @pubtype = publication_type FROM ##PublicationInfo SET @cmd = 'SELECT * INTO ##SubscriptionInfo FROM OPENROWSET(''SQLOLEDB'',''SERVER=(LOCAL);TRUSTED_CONNECTION=YES'' ,''SET FMTONLY OFF EXEC distribution.dbo.sp_replmonitorhelpsubscription @publisher=''''' + @publisher + ''''',@publication_type=' + CONVERT(CHAR(1), @pubtype) + ' with result sets ((status int, warning int, subscriber sysname, subscriber_db sysname, publisher_db sysname, publication sysname, publication_type int, subtype int, latency int, latencythreshold int, agentnotrunning int, agentnotrunningthreshold int, timetoexpiration int, expirationthreshold int, last_distsync datetime, distribution_agentname sysname, mergeagentname sysname, mergesubscriptionfriendlyname sysname, mergeagentlocation sysname, mergeconnectiontype int, mergePerformance int, mergerunspeed float, mergerunduration int, monitorranking int, distributionagentjobid binary(16), mergeagentjobid binary(16), distributionagentid int, distributionagentprofileid int, mergeagentid int, mergeagentprofileid int, logreaderagentname sysname, publisher sysname ))'')' --select @cmd EXEC sp_executesql @cmd select * from ##SubscriptionInfo ALTER TABLE ##SubscriptionInfo ADD PendingCmdCount INT NULL, EstimatedProcessTime INT NULL DECLARE cur_sub CURSOR READ_ONLY FOR SELECT @publisher, s.publisher_db, s.publication, s.subscriber, s.subscriber_db, s.subtype, s.distribution_agentname FROM ##SubscriptionInfo s OPEN cur_sub FETCH NEXT FROM cur_sub INTO @publisher, @publisher_db, @publication, @subscriber, @subscriber_db, @subtype, @JobName WHILE @@FETCH_STATUS = 0 BEGIN SET @cmd = 'SELECT @cmdcount=pendingcmdcount, @processtime=estimatedprocesstime FROM OPENROWSET(''SQLOLEDB'',''SERVER=(LOCAL);TRUSTED_CONNECTION=YES'' ,''SET FMTONLY OFF EXEC distribution.dbo.sp_replmonitorsubscriptionpendingcmds @publisher=''''' + @publisher + ''''',@publisher_db=''''' + @publisher_db + ''''',@publication=''''' + @publication + ''''',@subscriber=''''' + @subscriber + ''''',@subscriber_db=''''' + @subscriber_db + ''''',@subscription_type=' + CONVERT(CHAR(1), @subtype) + ' With result sets ((pendingcmdcount int, estimatedprocesstime int))'')' SET @ParmDefinition = N'@cmdcount INT OUTPUT, @processtime INT OUTPUT' select @cmd EXEC sp_executesql @cmd, @ParmDefinition, @cmdcount OUTPUT, @processtime OUTPUT SELECT @cmdcount, @processtime UPDATE ##SubscriptionInfo SET PendingCmdCount = @cmdcount, EstimatedProcessTime = @processtime WHERE subscriber_db = @subscriber_db INSERT INTO HCITools.mon.Replication_queue_history VALUES (@subscriber, @cmdcount, @processtime, GETDATE()) FETCH NEXT FROM cur_sub INTO @publisher, @publisher_db, @publication, @subscriber, @subscriber_db, @subtype, @JobName END CLOSE cur_sub DEALLOCATE cur_sub GO /***************************************************************/ /****** Create Procedure [Purge_repl_queue_hist] *******/ /***************************************************************/ IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[mon_purge_repl_queue_hist]') AND type in (N'P', N'PC')) DROP PROCEDURE [dbo].[mon_Purge_repl_queue_hist] GO CREATE PROCEDURE [dbo].[mon_Purge_repl_queue_hist] @in_debug INT = NULL AS /*============================================================================= Explication du traitement realise par la SP ------------------------------------------- To purge performance counters history in HCITools Contexte d'utilisation ---------------------- Job : DR92280 - Monitoring SQL Server Replication Parametres ---------- @in_debug Creation : 27.10.2021 / RTC Modifications : =============================================================================*/ DECLARE @delDate datetime = getdate()-30 DELETE FROM mon.Replication_queue_history WHERE RQH_log_date < @deldate GO /***************************************************************/ /** Create Job [DR92280 - Monitoring SQL Server Replication] **/ /***************************************************************/ /* Drop existing standard schedule for job */ declare @schedule_id int declare c_schedules cursor local forward_only static for select ss.schedule_id from msdb.dbo.sysjobschedules sjs INNER JOIN msdb.dbo.sysschedules ss ON sjs.schedule_id = ss.schedule_id AND ss.name NOT LIKE '%#SPEC#' INNER JOIN msdb.dbo.sysjobs sj ON sjs.job_id = sj.job_id WHERE sj.name = N'DR92280 - Monitoring SQL Server Replication' open c_schedules FETCH NEXT FROM c_schedules into @schedule_id while @@fetch_status = 0 begin IF ((select COUNT(*) from msdb.dbo.sysjobschedules where schedule_id=@schedule_id) = 1) EXEC msdb.dbo.sp_delete_schedule @schedule_id=@schedule_id, @force_delete = 1 FETCH NEXT FROM c_schedules into @schedule_id end close c_schedules deallocate c_schedules IF EXISTS (SELECT job_id FROM msdb.dbo.sysjobs_view WHERE name = N'DR92280 - Monitoring SQL Server Replication') EXEC msdb.dbo.sp_delete_job @job_name = N'DR92280 - Monitoring SQL Server Replication', @delete_unused_schedule=0 GO /* Creation Job and Steps*/ BEGIN TRANSACTION DECLARE @ReturnCode INT SELECT @ReturnCode = 0 IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name=N'[Uncategorized (Local)]' AND category_class=1) BEGIN EXEC @ReturnCode = msdb.dbo.sp_add_category @class=N'JOB', @type=N'LOCAL', @name=N'[Uncategorized (Local)]' IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback END /* Add Job */ DECLARE @jobId BINARY(16) EXEC @ReturnCode = msdb.dbo.sp_add_job @job_name=N'DR92280 - Monitoring SQL Server Replication', @enabled=1, @notify_level_eventlog=0, @notify_level_email=0, @notify_level_netsend=0, @notify_level_page=0, @delete_level=0, @description=N'27.10.2021 /RTC : Collect Data for replication monitoring', @category_name=N'[Uncategorized (Local)]', @start_step_id=1, @owner_login_name=N'sa', @job_id = @jobId OUTPUT IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback /* Add Step */ EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Empty step', @step_id=1, @cmdexec_success_code=0, @on_success_action=3, @on_success_step_id=0, @on_fail_action=3, @on_fail_step_id=0, @retry_attempts=0, @retry_interval=0, @os_run_priority=0, @subsystem=N'TSQL', @command=N'/*Empty step */', @database_name=N'master', @output_file_name=NULL, @flags=0, @database_user_name=NULL, @server=NULL, @additional_parameters=NULL, @proxy_id=NULL, @proxy_name=NULL IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback /* Add Step */ EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Repl monitor collect data', @step_id=2, @cmdexec_success_code=0, @on_success_action=3, @on_success_step_id=0, @on_fail_action=4, @on_fail_step_id=5, @retry_attempts=0, @retry_interval=0, @os_run_priority=0, @subsystem=N'TSQL', @command=N'exec [dbo].[mon_Get_Replication_Counters]', @database_name=N'HCITools', @output_file_name=NULL, @flags=0, @database_user_name=NULL, @server=NULL, @additional_parameters=NULL, @proxy_id=NULL, @proxy_name=NULL IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback /* Add Step */ EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Purge queue history', @step_id=3, @cmdexec_success_code=0, @on_success_action=3, @on_success_step_id=0, @on_fail_action=4, @on_fail_step_id=5, @retry_attempts=0, @retry_interval=0, @os_run_priority=0, @subsystem=N'TSQL', @command=N'exec [dbo].[mon_Purge_repl_queue_hist]', @database_name=N'HCITools', @output_file_name=NULL, @flags=0, @database_user_name=NULL, @server=NULL, @additional_parameters=NULL, @proxy_id=NULL, @proxy_name=NULL IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback /* Add Step */ EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Empty step for success', @step_id=4, @cmdexec_success_code=0, @on_success_action=1, @on_success_step_id=0, @on_fail_action=3, @on_fail_step_id=0, @retry_attempts=0, @retry_interval=0, @os_run_priority=0, @subsystem=N'TSQL', @command=N'/* EMpty step for success */', @database_name=N'master', @output_file_name=NULL, @flags=0, @database_user_name=NULL, @server=NULL, @additional_parameters=NULL, @proxy_id=NULL, @proxy_name=NULL IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback /* Add Step */ EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Send mail KO', @step_id=5, @cmdexec_success_code=0, @on_success_action=2, @on_success_step_id=0, @on_fail_action=2, @on_fail_step_id=0, @retry_attempts=0, @retry_interval=0, @os_run_priority=0, @subsystem=N'TSQL', @command=N'exec Get_Job_Error_Info @in_JobName = ''DR92280 - Monitoring SQL Server Replication'', @in_Recipients = ''DBA_operator''', @database_name=N'HCITools', @output_file_name=NULL, @flags=0, @database_user_name=NULL, @server=NULL, @additional_parameters=NULL, @proxy_id=NULL, @proxy_name=NULL IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId, @start_step_id = 1 IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback /* Add Standard Schedule */ EXEC @ReturnCode = msdb.dbo.sp_add_jobschedule @job_id=@jobId, @name=N'DR92280-DR', @enabled=1, @freq_type=4, @freq_interval=1, @freq_subday_type=4, @freq_subday_interval=10, @freq_relative_interval=0, @freq_recurrence_factor=0, @active_start_date=20210820, @active_end_date=99991231, @active_start_time=0, @active_end_time=235959 IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback /* Attach existing specific schedule for job */ declare @enabled_schedule int, @schedule_name nvarchar(50) declare c_schedules cursor local forward_only static for select enabled, name from msdb.dbo.sysschedules where name LIKE 'DR92280%' and name LIKE '%#SPEC#' open c_schedules FETCH NEXT FROM c_schedules into @enabled_schedule, @schedule_name while @@fetch_status = 0 begin EXEC @ReturnCode = msdb.dbo.sp_attach_schedule @job_id = @jobId, @schedule_name=@schedule_name IF(@enabled_schedule = 1) begin SET @schedule_name = SUBSTRING(@schedule_name,0,LEN(@schedule_name)-5) IF EXISTS (select name from msdb.dbo.sysschedules where name = @schedule_name) EXEC @ReturnCode = msdb.dbo.sp_update_schedule @name=@schedule_name, @enabled=0 end IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback FETCH NEXT FROM c_schedules into @enabled_schedule, @schedule_name end close c_schedules deallocate c_schedules EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId, @server_name = N'(local)' IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback COMMIT TRANSACTION GOTO EndSave QuitWithRollback: IF (@@TRANCOUNT > 0) ROLLBACK TRANSACTION EndSave: GO