I have a table called tblBOrderPaymentGiftVoucher that is replicated to 3 different subscriber servers.
this table is part of a publication that contains many tables, some very big. I can't afford to re-run the snapshot for this entire publication.
I need to run a batch update on this table though, without upsetting the replication, and with the best possible performance.
this is the table sctructure:
CREATE TABLE [dbo].[tblBOrderPaymentGiftVoucher](
[lngPaymentID] [int] NOT NULL,
[strVoucherNumber] [binary](24) NOT NULL,
[tsRowVersion] [timestamp] NULL,
CONSTRAINT [PK_tblBOrderPaymentGiftVoucher] PRIMARY KEY CLUSTERED
(
[lngPaymentID] ASC
)
the proble is that for some reason the data on the subscriber_server_1 is not the same as in the live server, for example have a look at the picture below, it shows data in the subscriber_1, too many zeros, the data on live is not like that.
I dont't know what has caused this.
what I have done to correct the situation, is:
1) copying the whole table from the live server to the subscriber1 server, and saving it into a database called tablebackups.
2) Stop the distribution agent for this publication
3) run a batch update to update data on the bocss2 database (the live database) from the tablebackups database (the copy of live system I have just copied over)
4) go to the distributor server and start the distributor agent job and wait for it to catch up
this is the script that I have successfully used to deal with the replication: successfully means the replication is still working fine even after applying the update
--on the main serve BOCSS\BOCSS
--find out the distributor
use bocss2 -- this is the live database
sp_helpdistributor
--SQLDIST\DIST
--distribution_BOCSS
-- stopping the distributor agent
-- on the distributor server
--select @@servername
--SQLDIST\DIST
-- find out what is the distributor job to be stopped
select msda.*
,sjv.*
--,sjs.*
from dbo.MSdistribution_agents as msda
inner join msdb.dbo.sysjobs_view as sjv
on msda.job_id = sjv.job_id
--inner join msdb.dbo.sysjobsteps as sjs
-- on sjv.job_id = sjs.job_id
where publication = 'Bocss2Finance'
--see what is running
exec sp_runningjobs
exec msdb.dbo.sp_stop_job @job_name = 'BOCSS\BOCSS-Bocss2-Bocss2Finance-SQLREPLON1\REP-38'
---------------
-- get the changes done
-- the update is run here
---------------
------------------------------------------
-- back to the distributor server
--SQLDIST\DIST
--distribution_BOCSS
------------------------------------------
exec msdb.dbo.sp_start_job @job_name = 'BOCSS\BOCSS-Bocss2-Bocss2Finance-SQLREPLON1\REP-38'
and this is the batch update script that I successfully used to update a table with 2.5 million rows
BEGIN TRY
DROP TABLE TableBackups.dbo.TMP_Paymentes
END TRY
BEGIN CATCH END CATCH
CREATE TABLE TableBackups.dbo.TMP_Paymentes
(I INT NOT NULL IDENTITY(1,1) primary key CLUSTERED,
lngPaymentID int NOT NULL)
SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SET DEADLOCK_PRIORITY HIGH
DECLARE @BATCH_SIZE BIGINT
DECLARE @MIN_Payment BIGINT
DECLARE @MAX_Payment BIGINT
DECLARE @Cur_PaymentID BIGINT
DECLARE @Cur_RowID BIGINT
DECLARE @Cur_FromPayment BIGINT
DECLARE @Cur_ToPayment BIGINT
DECLARE @ROWCOUNT INT
SET @BATCH_SIZE = 50000
SELECT @MAX_Payment = MAX(lngPaymentID)
FROM TableBackups.dbo.TMP_Paymentes
SELECT @Cur_FromPayment = lngPaymentID-1
FROM TableBackups.dbo.TMP_Paymentes
WHERE I = 1
SELECT @Cur_ToPayment = lngPaymentID
FROM TableBackups.dbo.TMP_Paymentes
WHERE I = @BATCH_SIZE
SELECT @Cur_RowID = @BATCH_SIZE
PRINT '----------------------------------------------'
PRINT '@MAX_Payment IS ' + CAST (@MAX_Payment AS VARCHAR)
PRINT '@Cur_FromPayment IS ' + CAST ( @Cur_FromPayment AS VARCHAR)
PRINT '@Cur_ToPayment IS ' + CAST (@Cur_ToPayment AS VARCHAR)
WHILE (1=1)
BEGIN
BEGIN TRY
BEGIN TRANSACTION
UPDATE B
SET B.strVoucherNumber = T.strVoucherNumber
from tablebackups.dbo.tblBOrderPaymentGiftVoucher T
INNER JOIN BOCSS2.DBO.tblBOrderPaymentGiftVoucher B
ON T.lngPaymentID = B.lngPaymentID
--AND T.STRVOUCHERNUMBER <> B.strVoucherNumber
WHERE
B.lngPaymentID > @Cur_FromPayment AND
B.lngPaymentID <= @Cur_ToPayment
SELECT @ROWCOUNT = @@ROWCOUNT
PRINT ' UPDATED ' + CAST (@ROWCOUNT AS VARCHAR)
PRINT '@Cur_FromPayment WAS ' + CAST ( @Cur_FromPayment AS VARCHAR)
PRINT '@Cur_ToPayment WAS ' + CAST (@Cur_ToPayment AS VARCHAR)
IF @ROWCOUNT = 0 BEGIN
IF @@TRANCOUNT > 0
COMMIT TRANSACTION
BREAK;
END
SELECT @Cur_FromPayment = @Cur_ToPayment
SELECT @Cur_RowID = @Cur_RowID + 50000
SELECT @Cur_ToPayment = lngPaymentID
FROM TableBackups.dbo.TMP_Paymentes
WHERE I = @Cur_RowID
IF (@Cur_ToPayment IS NULL) BEGIN
PRINT '@Cur_ToPayment OVERFLOWN ----'
SELECT @Cur_ToPayment = @MAX_Payment
PRINT '@Cur_ToPayment IS NOW ' + CAST (@Cur_ToPayment AS VARCHAR)
END
COMMIT;
END TRY
BEGIN CATCH
DECLARE @ERRORMESSAGE NVARCHAR(512),
@ERRORSEVERITY INT,
@ERRORNUMBER INT,
@ERRORSTATE INT,
@ERRORPROCEDURE SYSNAME,
@ERRORLINE INT,
@XASTATE INT
SELECT
@ERRORMESSAGE = ERROR_MESSAGE(),
@ERRORSEVERITY = ERROR_SEVERITY(),
@ERRORNUMBER = ERROR_NUMBER(),
@ERRORSTATE = ERROR_STATE(),
@ERRORPROCEDURE = ERROR_PROCEDURE(),
@ERRORLINE = ERROR_LINE()
SET @ERRORMESSAGE =
(
SELECT
'Error:' + convert(nvarchar(50),@ErrorNumber) + space(1) +
'Severity:' + convert(nvarchar(50),@ErrorSeverity) + space(1) +
'State:' + convert(nvarchar(50),@ErrorState) + space(1) +
'Routine_Name: ' + isnull(@ErrorProcedure,'') + space(1) +
'Line:' + convert(nvarchar(50),@ErrorLine) + space(1) +
'Message: ' + @ErrorMessage + space(1) +
'ExecutedAs:' + SYSTEM_USER + space(1) +
'Database:' + DB_NAME() + space(1) +
'OSTime:' + convert(nvarchar(25),CURRENT_TIMESTAMP,121)
)
SELECT @XASTATE = XACT_STATE();
IF @XASTATE = 1
ROLLBACK TRANSACTION
RAISERROR (@ERRORMESSAGE,16,1)
BREAK;
END CATCH
END
--DROP TABLE TableBackups.dbo.TMP_Paymentes
SET NOCOUNT OFF
questions:
1) the replication is working fine, but is there any other thing I should have done and missed?
2) being the most objective, and not opinion based possible, to comply with the rules of the forum, are there suggestions for improving the batch process?
3) These are the set of changes in the replication I was intended to do I have only done 1,3,4, and it is all working (so far as I know )
This is how I think I’d go about it:
Stop the distributor agent for Bocss2Finance
Set the distributor profile to ignore errors
Make the fixes to the subscriber article
Start distributor agent
Wait for the errors to pass
Stop the distributor Agent
Change the distributor agent profile back to what it was previously
Start the distributor agent.