Quantcast
Channel: StackExchange Replication Questions
Viewing all articles
Browse latest Browse all 17268

subscriber table needs to be updated - how to use a batch process AND how not to upset the replication while doing it?

$
0
0

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.

enter image description here

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:

  1. Stop the distributor agent for Bocss2Finance

  2. Set the distributor profile to ignore errors

  3. Make the fixes to the subscriber article

  4. Start distributor agent

  5. Wait for the errors to pass

  6. Stop the distributor Agent

  7. Change the distributor agent profile back to what it was previously

  8. Start the distributor agent.


Viewing all articles
Browse latest Browse all 17268

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>