Sometimes business needs to move a distribution db to a new MS SQL Server instance. The most common solution would be to drop and recreate a replication topology with a new distributor instance.However, you will need to synch data on subscribers afterwards or reapply newly generated replication snapshots.This is not very graceful approach and can take hours to complete if publications are highly transactional and articles contain lots of data. Moreover, it can cause downtime in production systems if the latest data is retrieved by customers on subscribers. A better solution would be to restore existing distribution db on the new distributor using the following step-by-step guide:
1.Create distribution database
We need to create a database on a new distributor instance.
--sqlcmd command to open connection to a new distributor: :CONNECT $(NewDistributor) GO --sql code to create a new distribution db on a new distributor instance: EXEC sp_adddistributiondb @database = N'$(DistributionDB)', @data_folder = N'E:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA', @log_folder = N'E:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA', @log_file_size = 2, @min_distretention = 0, @max_distretention = 72, @history_retention = 48, @security_mode = 1 GO
Note: All sql code examples has to be executed in sqlcmd mode with correct $(NewDistributor), $(PUBLISHER),$(PUBLISHER_DB), $(PublicationName) ,$(SUBSCRIBER),$(SUBSCRIPTION_DB) , $(DistributionDB),$(CURRENT_DISTRIBUTOR), $(LogreaderAgentLoginName), $(DistributorAgentLoginName), @working_directory variables values which are specific for your db servers estate.
2.Add the publisher
We need to add the publisher values on a new distributor instance.
--sqlcmd command to open connection to a new distributor :CONNECT $(NewDistributor) GO use master GO --sql code to add a publisher to a new distribution db on a new distributor instance: EXEC sp_adddistpublisher @publisher = N'$(PUBLISHER)', @distribution_db = N'$(DistributionDB)', @security_mode = 1, @working_directory = N'\\VL1DB020\ReplData', @thirdparty_flag = 0, @publisher_type = N'MSSQLSERVER' GO
3. Linked Servers
Create the missing linked servers on the new distributor.
--sqlcmd command to open connection to a new distributor :CONNECT $(NewDistributor) GO use master GO DECLARE @server_name sysname; -- sql code to create linked server and access data from the current distributor EXEC master.dbo.sp_addlinkedserver @server = '$(CURRENT_DISTRIBUTOR)', @srvproduct=N'SQL Server' ; -- get one missing linked server on the new distributor server; select top 1 @server_name=srvname from [$(CURRENT_DISTRIBUTOR)].master..sysservers except select srvname from master..sysservers
-- sql code to create missing linked server on the new distributor. EXEC master.dbo.sp_addlinkedserver @server = @server_name, @srvproduct=N'SQL Server' ;
3.1. Check Profiles
Make sure msdb.dbo.MSagent_profiles are matching between distributors.
--sqlcmd command to open connection to a new distributor :CONNECT $(NewDistributor) GO use master GO -- retrieve all different profiles from the current distributor select * from [$(CURRENT_DISTRIBUTOR)].msdb.dbo.MSagent_profiles except select * from msdb.dbo.MSagent_profiles
4.Set distribution db to full recovery mode
We need to change the recovery model and set the sync with backup option.
--sqlcmd command to open connection to a current distributor: :CONNECT [$(CURRENT_DISTRIBUTOR)] GO USE [master] --sqlcmd command to set distribution db options: ALTER DATABASE [$(DistributionDB)] SET RECOVERY FULL WITH NO_WAIT exec sp_replicationdboption '$(DistributionDB)', 'sync with backup', true
5.Create missing logins
This script will create the missing logins on the new distributor and add distribution agent and log reader agent accounts to db_owner role on the distribution db:
--sqlcmd command to open connection to a current distributor: :CONNECT [$(NEWDISTRIBUTOR)] GO USE [master] IF NOT EXISTS (SELECT * FROM master.sys.server_principals WHERE [name] = '$(DistributorAgentLoginName)') BEGIN print 'Creating $(DistributorAgentLoginName) login ' CREATE LOGIN [$(DistributorAgentLoginName)] FROM WINDOWS WITH DEFAULT_DATABASE=[master] END GO IF NOT EXISTS (SELECT * FROM master.sys.server_principals WHERE [name] = '$(LogReaderAgentLoginName)') BEGIN print 'Creating $(LogreaderAgentLoginName) login ' CREATE LOGIN [$(LogreaderAgentLoginName)] FROM WINDOWS WITH DEFAULT_DATABASE=[master] END
use [$(DistributionDB)] GO IF NOT EXISTS ( SELECT * FROM sys.database_principals WHERE name = '$(DistributorAgentLoginName)' ) BEGIN print 'Creating $(DistributorAgentLoginName) db user' CREATE USER [$(DistributorAgentLoginName)] FOR LOGIN [$(DistributorAgentLoginName)] END IF NOT EXISTS ( SELECT * FROM sys.database_principals WHERE name = '$(LogreaderAgentLoginName)' ) BEGIN print 'Creating $(LogreaderAgentLoginName) db user' CREATE USER [$(LogreaderAgentLoginName)] FOR LOGIN [$(LogreaderAgentLoginName)] END --Add Roles print 'Add $(LogreaderAgentLoginName) db user to db_owner role' EXEC [sp_addrolemember] @rolename = 'db_owner', @membername = '$(LogreaderAgentLoginName)' GO print 'Add $(DistributorAgentLoginName) db user to db_owner role' EXEC [sp_addrolemember] @rolename = 'db_owner', @membername = '$(DistributorAgentLoginName)' GO
6.Create missing distribution agent login
We now need to create a lotin and then add it to the db_owner role on the subscriber dbs for pull subscriptions.
--sqlcmd command to open connection to a current distributor: :CONNECT [$(SUBSCRIBER)] GO USE [master] IF NOT EXISTS (SELECT * FROM master.sys.server_principals WHERE [name] = '$(DistributorAgentLoginName)') BEGIN print 'Creating $(DistributorAgentLoginName) login ' CREATE LOGIN [$(DistributorAgentLoginName)] FROM WINDOWS WITH DEFAULT_DATABASE=[master] END GO use [$(DistributionDB)] GO IF NOT EXISTS ( SELECT * FROM sys.database_principals WHERE name = '$(DistributorAgentLoginName)' ) BEGIN print 'Creating $(DistributorAgentLoginName) db user' CREATE USER [$(DistributorAgentLoginName)] FOR LOGIN [$(DistributorAgentLoginName)] END --Add Roles print 'Adding $(DistributorAgentLoginName) db user to db_owner role' EXEC [sp_addrolemember] @rolename = 'db_owner', @membername = '$(DistributorAgentLoginName)' GO
7.Stop/disable replication jobs
We need to stop or disable the replication jobs on the current distributor and pull subscribers.
Example:
--sqlcmd command to open connection to a current distributor: :CONNECT $(CURRENT_DISTRIBUTOR) GO --sql batch to stop and disable replication sql jobs: DECLARE @JobName sysname DECLARE @CMD varchar(1000) DECLARE @Name VARCHAR(200) ; DECLARE Purge CURSOR FOR SELECT j.name FROM [msdb].[dbo].[sysjobs] j where j.name like '$(PUBLISHER)%' OPEN Purge ; FETCH NEXT FROM Purge INTO @Name ; WHILE @@FETCH_STATUS = 0 BEGIN EXEC msdb.dbo.sp_stop_job @job_name = @NAME WAITFOR DELAY '00:00:03' exec msdb.dbo.sp_update_job @job_name = @NAME, @enabled = 0 FETCH NEXT FROM Purge INTO @Name ; END CLOSE Purge ; DEALLOCATE Purge ;
Also you can use SSMS to connect to pull subscribers and current distributor. Later open Job Activity Monitor and disable related replication jobs.
8.Backup distribution db
We always need a backup.
--sqlcmd command to open connection to a current distributor: :CONNECT $(CURRENT_DISTRIBUTOR) GO --sql command to backup distribution db on a current distributor: BACKUP DATABASE [$(DistributionDB)] TO DISK = N'E:\Backup\$(DistributionDB)_FULL.bak' WITH NOFORMAT, INIT, NAME = N'$(DistributionDB)-Full Database Backup', SKIP, NOREWIND, NOUNLOAD, STATS = 10 GO BACKUP LOG [$(DistributionDB)] TO DISK = N'E:\Backup\$(DistributionDB)_LOG.bak' WITH NOFORMAT, INIT, NAME = N'$(DistributionDB)-Full Log Backup', SKIP, NOREWIND, NOUNLOAD, STATS = 10 GO
9.Restore distribution db on the new distributor instance:
Now we need to restore the old distribution database on the new instance so it can be used.
--sqlcmd command to open connection to a new distributor: :CONNECT $(NewDistributor) GO --sql command to restore distribution db on a new distributor instance: USE [master] GO -- make sure file paths are correct on your distributor -- set db to single user mode ALTER DATABASE [$(DistributionDB)] SET single_user WITH ROLLBACK IMMEDIATE; --restore distribution database on new distributor RESTORE DATABASE [$(DistributionDB)] FROM DISK = 'e:\backup\$(DistributionDB)_FULL.bak' WITH FILE = 1, MOVE N'$(DistributionDB)' TO N'E:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\$(DistributionDB).MDF', MOVE N'$(DistributionDB)_log' TO N'L:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\$(DistributionDB).LDF', NOUNLOAD, REPLACE, STATS = 5, NORECOVERY -- restore database log now RESTORE LOG [$(DistributionDB)] FROM DISK = 'e:\backup\$(DistributionDB)_LOG.bak' WITH FILE = 1, MOVE N'$(DistributionDB)' TO N'E:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\$(DistributionDB).MDF', MOVE N'$(DistributionDB)_log' TO N'L:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\$(DistributionDB).LDF', NOUNLOAD, REPLACE, STATS = 5, KEEP_REPLICATION -- set db to multiuser access mode ALTER DATABASE [$(DistributionDB)] SET multi_user
10.Update MSpublisher_databases table with correct publisher id:
A last update that will get things ready to sync with the publisher.
--sqlcmd command to open connection to a new distributor: :CONNECT $(NewDistributor) GO use [$(DistributionDB)] GO -- sql commands to set publisher_id values declare @srvid smallint select @srvid = srvid from master..sysservers where upper(srvname) = upper(N'$(PUBLISHER)') update t set t.publisher_id =@srvid FROM [$(DistributionDB)].[dbo].[MSpublisher_databases] t
11.Script out log reader/snapshot jobs
We need the scripts for the jobs from the current distributor and create these jobs in disabled state on a new distributor with updated server names in all jobs steps.
--sqlcmd command to open connection to a new distributor: :CONNECT $(NewDistributor) GO --create log reader job on msdb USE [msdb] GO BEGIN TRANSACTION DECLARE @ReturnCode INT SELECT @ReturnCode = 0 IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name=N'REPL-LogReader' AND category_class=1) BEGIN EXEC @ReturnCode = msdb.dbo.sp_add_category @class=N'JOB', @type=N'LOCAL', @name=N'REPL-LogReader' IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback END DECLARE @jobId BINARY(16) EXEC @ReturnCode = msdb.dbo.sp_add_job @job_name=N'$(Publisher)-$(Publisher_DB)-2', @enabled=1, @notify_level_eventlog=0, @notify_level_email=0, @notify_level_netsend=0, @notify_level_page=0, @delete_level=0, @description=N'No description available.', @category_name=N'REPL-LogReader', @owner_login_name=N'distributor_admin', @job_id = @jobId OUTPUT IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Log Reader Agent startup message.', @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'sp_MSadd_logreader_history @perfmon_increment = 0, @agent_id = 2, @runstatus = 1, @comments = N''Starting agent.''', @server=N'$(PUBLISHER)', @database_name=N'$(DISTRIBUTIONDB)', @flags=0 IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Run agent.', @step_id=2, @cmdexec_success_code=0, @on_success_action=1, @on_success_step_id=0, @on_fail_action=3, @on_fail_step_id=0, @retry_attempts=2147483647, @retry_interval=1, @os_run_priority=0, @subsystem=N'LogReader', @command=N'-Publisher [$(PUBLISHER)] -PublisherDB [$(Publisher_DB)] -Distributor [$(NewDistributor)] -DistributorSecurityMode 1 ', @server=N'$(PUBLISHER)', @database_name=N'$(DISTRIBUTIONDB)', @flags=0 IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Detect nonlogged agent shutdown.', @step_id=3, @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'sp_MSdetect_nonlogged_shutdown @subsystem = ''LogReader'', @agent_id = 2', @server=N'$(PUBLISHER)', @database_name=N'$(DISTRIBUTIONDB)', @flags=0 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 EXEC @ReturnCode = msdb.dbo.sp_add_jobschedule @job_id=@jobId, @name=N'Replication agent schedule.', @enabled=1, @freq_type=4, @freq_interval=1, @freq_subday_type=4, @freq_subday_interval=1, @freq_relative_interval=0, @freq_recurrence_factor=0, @active_start_date=20130405, @active_end_date=99991231, @active_start_time=160618, @active_end_time=160617 IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback COMMIT TRANSACTION GOTO EndSave QuitWithRollback: IF (@@TRANCOUNT > 0) ROLLBACK TRANSACTION EndSave: GO
12.Change publisher_id
We need to change the publisher_id in the restored distribution db
--sqlcmd command to open connection to a new distributor: :CONNECT $(NewDistributor) GO use [$(DistributionDB)] GO -- sql commands to set publisher_id declare @srvid smallint select @srvid = srvid from master..sysservers where upper(srvname) = upper(N'$(PUBLISHER)') --set correct publisher_id update t set t. publisher_id = @srvid from dbo.MSpublications t
13.Change subscriber_id/publisher_id
We also need to change ids in the restored distribution db.
--sqlcmd command to open connection to a new distributor: :CONNECT $(NewDistributor) GO use [$(DistributionDB)] GO -- sql commands to set correct subscriber_id and publisher_id values declare @srvid smallint select @srvid = srvid from master..sysservers where upper(srvname) = upper(N'$(PUBLISHER)') --set correct subscriber_id and publisher_id values UPDATE t SET t.subscriber_id = ls.server_id, publisher_id = @srvid from $(DistributionDB).dbo.MSdistribution_agents t left join [$(Current_Distributor)].master.sys.servers ss on ss.server_id = t.subscriber_id left join master.sys.servers ls on ls.name = ss.name --set correct subscriber_id and publisher_id values UPDATE t SET t.subscriber_id = ls.server_id , publisher_id = @srvid FROM [$(DistributionDB)].dbo.MSsubscriptions t left join [$(Current_Distributor)].master.sys.servers ss on ss.server_id = t.subscriber_id left join master.sys.servers ls on ls.name = ss.name GO
14.Script out push subscription jobs
We need the jobs on the current distributor and create these jobs in disabled state on a new distributor with updated server names in all jobs steps.
--sqlcmd command to open connection to a new distributor: :CONNECT $(NewDistributor) GO Use msdb GO --create replication distribution agent jobs on the new subscriber: BEGIN TRANSACTION DECLARE @ReturnCode INT SELECT @ReturnCode = 0 IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name=N'REPL-Distribution' AND category_class=1) BEGIN EXEC @ReturnCode = msdb.dbo.sp_add_category @class=N'JOB', @type=N'LOCAL', @name=N'REPL-Distribution' IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback END DECLARE @jobId BINARY(16) EXEC @ReturnCode = msdb.dbo.sp_add_job @job_name=N'$(Publisher)-$(Publisher_DB)-$(PublicationName)-$(Subscriber) -7', @enabled=1, @notify_level_eventlog=0, @notify_level_email=0, @notify_level_netsend=0, @notify_level_page=0, @delete_level=0, @description=N'No description available.', @category_name=N'REPL-Distribution', @owner_login_name=N'distributor_admin', @job_id = @jobId OUTPUT IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Distribution Agent startup message.', @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'sp_MSadd_distribution_history @perfmon_increment = 0, @agent_id = 7, @runstatus = 1, @comments = N''Starting agent.''', @server=N'$(NewDistributor)', @database_name=N'$(DistributionDB)', @flags=0 IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Run agent.', @step_id=2, @cmdexec_success_code=0, @on_success_action=1, @on_success_step_id=0, @on_fail_action=3, @on_fail_step_id=0, @retry_attempts=2147483647, @retry_interval=1, @os_run_priority=0, @subsystem=N'Distribution', @command=N'-Subscriber [$(SUBSCRIBER)] -SubscriberDB [$(SUBSCRIPTION_DB)] -Publisher [$(PUBLISHER)] -Distributor [$(NewDistributor)] -DistributorSecurityMode 1 -Publication [$(PublicationName)] -PublisherDB [$(Publisher_DB)] ', @server=N'$(NewDistributor)', @database_name=N'$(DISTRIBUTIONDB)', @flags=0 IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Detect nonlogged agent shutdown.', @step_id=3, @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'sp_MSdetect_nonlogged_shutdown @subsystem = ''Distribution'', @agent_id = 7', @server=N'$(NEWDISTRIBUTOR)', @database_name=N'$(DISTRIBUTIONDB)', @flags=0 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 EXEC @ReturnCode = msdb.dbo.sp_add_jobschedule @job_id=@jobId, @name=N'Replication agent schedule.', @enabled=1, @freq_type=4, @freq_interval=1, @freq_subday_type=4, @freq_subday_interval=1, @freq_relative_interval=0, @freq_recurrence_factor=0, @active_start_date=20130405, @active_end_date=99991231, @active_start_time=160241, @active_end_time=160240 --@schedule_uid=N'83abb125-f445-4e5b-bbed-d4703949e2fc' IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback --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
15.Alter pull subscribers replication jobs
We need to update the jobs to set new distributor name.
--sqlcmd command to open connection to a pull subscriber: :CONNECT $(SUBSCRIBER) GO use [$(SUBSCRIPTION_DB)] GO --update replication jobs properties: EXEC msdb.dbo.sp_update_jobstep @job_id=N'9f743215-ee8a-4f5e-85e5-dbbac4a2d329', @step_id=1 , @command=N'-Publisher $(Publisher) -PublisherDB [$(Publisher_DB)] -Publication [$(PublicationName)] -Distributor [$(NewDistributor)] -SubscriptionType 1 -Subscriber [$(Subscriber)] -SubscriberSecurityMode 1 -SubscriberDB [$(SUBSCRIPTION_DB)]' GO
16.Alter the distributor name on pull subscribers:
The following sql code has to be executed in sqlcmd mode with correct $(NewDistributor),$(PUBLISHER),$(PUBLISHER_DB), $(PublicationName) ,$(SUBSCRIBER),$(SUBSCRIPTION_DB), $(DistributionDB) variables values:
--sqlcmd command to open connection to a pull subscriber: :CONNECT $(SUBSCRIBER) GO use [$(SUBSCRIPTION_DB)] GO ---execute sp to update pull subscriptions properties: EXEC sp_change_subscription_properties @publisher = '$(PUBLISHER)' , @publisher_db = '$(PUBLISHER_DB)' , @publication = '$(PublicationName)' , @property = 'distributor' , @value = '$(NewDistributor)' GO
17.Update log reader agent entries
We need to update values to ensure the replication monitor is working.
--sqlcmd command to open connection to a new distributor: :CONNECT $(NewDistributor) GO use [$(DistributionDB)] GO -- sql command to set correct publisher_id values to make replication monitor working on the new distributor. declare @srvid smallint select @srvid = srvid from master..sysservers where upper(srvname) = upper(N'$(PUBLISHER)') update t set t.publisher_id = @srvid FROM [$(DistributionDB)].[dbo].[MSlogreader_agents] t --set correct job_id and job_step_uid values update t set t.job_id = sj.job_id, t.job_step_uid = sjs.step_uid from dbo.MSlogreader_agents t left join dbo.MSreplication_monitordata sm on sm.agent_name = t.name left join msdb.dbo.sysjobs sj on sj.name = t.name left join msdb.dbo.sysjobsteps sjs on sj.job_id = sjs.job_id and sjs.step_id = 2
18. Change distributor name
We need to change the name on the publisher.
--sqlcmd command to open connection to a publisher: :CONNECT $(PUBLISHER) GO use [master] GO -- sql commands to assign a new distributor name on a publisher DECLARE @distributor sysname select @distributor = upper('$(NewDistributor)') EXECUTE sys.sp_setnetname 'repl_distributor', @distributor
19.Enable subscriber jobs
We need to enable the jobs one-by-one and resolve permission issues if they exist.
--sqlcmd command to open connection to a current distributor: :CONNECT $(SUBSCRIBER) GO --sql batch to start and enable replication sql jobs on subscriber: DECLARE @JobName sysname DECLARE @CMD varchar(1000) DECLARE @Name VARCHAR(200) ; DECLARE Purge CURSOR FOR SELECT j.name FROM [msdb].[dbo].[sysjobs] j where j.name like '$(PUBLISHER)%' -- filter out and retrieve only replication jobs OPEN Purge ; FETCH NEXT FROM Purge INTO @Name ; WHILE @@FETCH_STATUS = 0 --loop BEGIN --enable replication sql job exec msdb.dbo.sp_update_job @job_name = @NAME, @enabled = 1 --start replication sql job EXEC msdb.dbo.sp_start_job @job_name = @NAME WAITFOR DELAY '00:00:59' FETCH NEXT FROM Purge INTO @Name ; END CLOSE Purge ; DEALLOCATE Purge ;
20.Enable Log-reader agent jobs
We now need to enable these jobs one-by-one and resolve any permission issues.
--sqlcmd command to open connection to a new distributor: :CONNECT $(NewDistributor) GO use msdb go DECLARE @JobName sysname SET @JobName = '$(LogReaderJobName)' – find out job name on distributor ---enable log-reader agent jobs exec msdb.dbo.sp_update_job @job_name = @JobName, @enabled = 1 GO
21. Add distribution db to backup schedule.
Now you need to add the distribution db to the backup routine and do regular db backups.
22. If no errors exist then delete disabled replication jobs on the old distributor.
Connect to the old distributor via SSMS, open Job Activity Monitor and delete the disabled replication jobs.
23. Drop the old publisher
We need to drop the publisher on the old distributor server.
--sqlcmd command to open connection to the distributor: :CONNECT $(OLD_DISTRIBUTOR) go use master go --sql command to remove publisher info on the old distributor: Exec sp_dropdistpublisher @publisher = '$(PUBLISHER)' , @no_checks = 1 , @ignore_distributor = 0
24. Open replication monitor and verify transactional replication activity.
Replication monitor view snapshot after the change completion:
There should be no errors or red alerts shown in replication monitor if all above steps are done properly with correct variables values. Replication jobs can be in running or not running states.
Conclusion
This custom solution allows sql dbas quickly move distribution db to a new sql server instance without losing data and having downtime in production environment. Moreover, solution can be quickly reverted back if something goes wrong during the change and implementer has not started step 20. Bear in mind that if log-reader agents are enabled and new transactions have been processed on the new distributor then correct way to rollback would be to drop and recreate replication objects and do data synchronization afterwards.