Replication Subscriber Issue

  • We have a database which is push subscriber for a publisher in other environment (other group in my company)

    In order to audit the dml changes in subscriber tables I have created triggers on some of the tables to track the changes and inserts into the other database in th same instance.

    but the issue is they are dissapearing when they are re-initializing the all the subscribers.

    How to prevent triggers from dissapearing?

    [font="Tahoma"]
    --SQLFRNDZ[/url]
    [/font]

  • You will have to change the publication (article) and stop the article behaviour of dropping the object upon reinitialisation. This is the default behaviour for all new articles.

    http://msdn.microsoft.com/en-us/library/ms175980.aspx

    pre_creation_cmd -Pre-creation command that can drop, delete, or truncate the destination table before synchronization is applied.

    none -Does not use a command.

    drop -Drops the destination table.

    delete -Deletes the destination table.

    truncate -Truncates the destination table.

  • How do you re-initialize? Snapshot or from backup?

    If you initialize from backup you'll need to re-create the triggers everytime (since your audit tables are in another DB they'll not be affected).

    If you re-initialize from snapshot do you drop and re-create the articles or delete/truncate them?

    If you are dropping them (the @pre_creation_cmd parameter to sp_addarticle which defaults to a drop) then that would be why your triggers are vanishing.

    You can either change the @pre_creation_cmd to truncate (will not help if you make schema changes on the publisher and want these to flow down) or put in a script to create the triggers whenever a snapshot is created (the @post_snapshot_script parameter to sp_addpublication or using sp_changepublication)

    Also consider the performance impact of having triggers on subscriber tables (if you have something like transactional replication setup). For e.g. a 100,000 row update/insert/delete on the publisher table will translate to 100,000 commands individually applied which translates to 100,000 invocations of your trigger.

  • This is true but it is not possible in our environment as publisher is having multiple subscribers and different requirements.

    We can make changes only on our end. Can you please suggest me any other way we can do on our end.

    I do tried CDC but unabled to enable on the table , throwing error server principle is unable to access under current security context.

    [font="Tahoma"]
    --SQLFRNDZ[/url]
    [/font]

  • winash (9/7/2011)


    How do you re-initialize? Snapshot or from backup?

    using snapshot

    If you initialize from backup you'll need to re-create the triggers everytime (since your audit tables are in another DB they'll not be affected).

    If you re-initialize from snapshot do you drop and re-create the articles or delete/truncate them?

    they are re-initilising with create new snapshot

    If you are dropping them (the @pre_creation_cmd parameter to sp_addarticle which defaults to a drop) then that would be why your triggers are vanishing.

    You can either change the @pre_creation_cmd to truncate (will not help if you make schema changes on the publisher and want these to flow down) or put in a script to create the triggers whenever a snapshot is created (the @post_snapshot_script parameter to sp_addpublication or using sp_changepublication)

    Also consider the performance impact of having triggers on subscriber tables (if you have something like transactional replication setup). For e.g. a 100,000 row update/insert/delete on the publisher table will translate to 100,000 commands individually applied which translates to 100,000 invocations of your trigger.

    this database is not transactional that much and the updates and changes are not many in a day.

    approx. 1000 rows in day are updateble

    [font="Tahoma"]
    --SQLFRNDZ[/url]
    [/font]

  • You could include a post snapshot script to reapply the triggers and any depandancies.

    http://technet.microsoft.com/en-us/library/ms188413.aspx

    sp_changepublication

    post_snapshot_script

  • Do I have any other way that I can re-create a job to create triggers when there is a re-initialisation using sanpshot.

    Intension is how would I detect the re-initialization ?

    and then kick the job to re-create the triggers

    Any base Idea would be help ful.

    [font="Tahoma"]
    --SQLFRNDZ[/url]
    [/font]

  • @SQLFRNDZ (9/7/2011)


    Do I have any other way that I can re-create a job to create triggers when there is a re-initialisation using sanpshot.

    Intension is how would I detect the re-initialization ?

    and then kick the job to re-create the triggers

    Any base Idea would be help ful.

    You could do it in a sql agent job.

    This is some of the code of the test I did to prove the concept to you. You could embed this in a stored proc and call the proc from te jobstep to make the job a bit more managable.

    declare @sqlcmd varchar(8000)

    DECLARE @NewLineChar AS CHAR(2) = CHAR(13) + CHAR(10)

    SET @sqlcmd = 'CREATE TRIGGER [dbo].[test_trg] ON [dbo].[testtable]' + @NewLineChar

    SET @sqlcmd = @sqlcmd +'FOR INSERT' + @NewLineChar

    SET @sqlcmd = @sqlcmd +'AS' + @NewLineChar

    SET @sqlcmd = @sqlcmd +'begin' + @NewLineChar

    SET @sqlcmd = @sqlcmd +'return' + @NewLineChar

    SET @sqlcmd = @sqlcmd +'end'

    /****** Object: Trigger [test_trg] Script Date: 09/08/2011 09:16:31 ******/

    IF NOT EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[dbo].[test_trg]'))

    exec (@sqlcmd)

    and this is the job

    USE [msdb]

    GO

    /****** Object: Job [ReCreate Triggers] Script Date: 09/08/2011 09:22:55 ******/

    BEGIN TRANSACTION

    DECLARE @ReturnCode INT

    SELECT @ReturnCode = 0

    /****** Object: JobCategory [[Uncategorized (Local)]]] Script Date: 09/08/2011 09:22:55 ******/

    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

    DECLARE @jobId BINARY(16)

    EXEC @ReturnCode = msdb.dbo.sp_add_job @job_name=N'ReCreate Triggers',

    @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'[Uncategorized (Local)]',

    @owner_login_name=N'sa', @job_id = @jobId OUTPUT

    IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback

    /****** Object: Step [Recreate insert trigger on test] Script Date: 09/08/2011 09:22:55 ******/

    EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Recreate insert trigger on test',

    @step_id=1,

    @cmdexec_success_code=0,

    @on_success_action=1,

    @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'declare @sqlcmd varchar(8000)

    DECLARE @NewLineChar AS CHAR(2) = CHAR(13) + CHAR(10)

    SET @sqlcmd = ''CREATE TRIGGER [dbo].[test_trg] ON [dbo].[testtable]'' + @NewLineChar

    SET @sqlcmd = @sqlcmd +''FOR INSERT'' + @NewLineChar

    SET @sqlcmd = @sqlcmd +''AS'' + @NewLineChar

    SET @sqlcmd = @sqlcmd +''begin'' + @NewLineChar

    SET @sqlcmd = @sqlcmd +''return'' + @NewLineChar

    SET @sqlcmd = @sqlcmd +''end''

    /****** Object: Trigger [test_trg] Script Date: 09/08/2011 09:16:31 ******/

    IF NOT EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N''[dbo].[test_trg]''))

    exec (@sqlcmd)',

    @database_name=N'Test',

    @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_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

    You could either schedule the job as it wont do anything unless the trigger is missing or you could create a ddl trigger for table creation on the database as the database (and trigger) will be unaffected by reinitialisation.

    CREATE TRIGGER [db_recreatetriggers]

    ON DATABASE

    FOR CREATE_TABLE

    begin

    exec sp_start_job @job_name = 'ReCreate Triggers'

    end

    go

  • @SQLFRNDZ (9/7/2011)


    We have a database which is push subscriber for a publisher in other environment (other group in my company)

    In order to audit the dml changes in subscriber tables I have created triggers on some of the tables to track the changes and inserts into the other database in th same instance.

    but the issue is they are dissapearing when they are re-initializing the all the subscribers.

    How to prevent triggers from dissapearing?

    I saw you getting pretty good advices to your question. I have adopted a generic approach. When I need to generate a snapshot for re-initializing, I always choose to use 'truncate destination object' if it exists.

    This way I can maintain the needs of subscriber. You need different indexes and statistics on publisher table or subscriber table due to different nature of their use. so if i use default option, i loose all indexes and statistics for any application using my subscription tables thus generating bad query plans.

    Thanks

    Chandan

  • MysteryJimbo (9/8/2011)


    @SQLFRNDZ (9/7/2011)


    Do I have any other way that I can re-create a job to create triggers when there is a re-initialisation using sanpshot.

    Intension is how would I detect the re-initialization ?

    and then kick the job to re-create the triggers

    Any base Idea would be help ful.

    You could do it in a sql agent job.

    This is some of the code of the test I did to prove the concept to you. You could embed this in a stored proc and call the proc from te jobstep to make the job a bit more managable.

    declare @sqlcmd varchar(8000)

    DECLARE @NewLineChar AS CHAR(2) = CHAR(13) + CHAR(10)

    SET @sqlcmd = 'CREATE TRIGGER [dbo].[test_trg] ON [dbo].[testtable]' + @NewLineChar

    SET @sqlcmd = @sqlcmd +'FOR INSERT' + @NewLineChar

    SET @sqlcmd = @sqlcmd +'AS' + @NewLineChar

    SET @sqlcmd = @sqlcmd +'begin' + @NewLineChar

    SET @sqlcmd = @sqlcmd +'return' + @NewLineChar

    SET @sqlcmd = @sqlcmd +'end'

    /****** Object: Trigger [test_trg] Script Date: 09/08/2011 09:16:31 ******/

    IF NOT EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[dbo].[test_trg]'))

    exec (@sqlcmd)

    and this is the job

    USE [msdb]

    GO

    /****** Object: Job [ReCreate Triggers] Script Date: 09/08/2011 09:22:55 ******/

    BEGIN TRANSACTION

    DECLARE @ReturnCode INT

    SELECT @ReturnCode = 0

    /****** Object: JobCategory [[Uncategorized (Local)]]] Script Date: 09/08/2011 09:22:55 ******/

    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

    DECLARE @jobId BINARY(16)

    EXEC @ReturnCode = msdb.dbo.sp_add_job @job_name=N'ReCreate Triggers',

    @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'[Uncategorized (Local)]',

    @owner_login_name=N'sa', @job_id = @jobId OUTPUT

    IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback

    /****** Object: Step [Recreate insert trigger on test] Script Date: 09/08/2011 09:22:55 ******/

    EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Recreate insert trigger on test',

    @step_id=1,

    @cmdexec_success_code=0,

    @on_success_action=1,

    @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'declare @sqlcmd varchar(8000)

    DECLARE @NewLineChar AS CHAR(2) = CHAR(13) + CHAR(10)

    SET @sqlcmd = ''CREATE TRIGGER [dbo].[test_trg] ON [dbo].[testtable]'' + @NewLineChar

    SET @sqlcmd = @sqlcmd +''FOR INSERT'' + @NewLineChar

    SET @sqlcmd = @sqlcmd +''AS'' + @NewLineChar

    SET @sqlcmd = @sqlcmd +''begin'' + @NewLineChar

    SET @sqlcmd = @sqlcmd +''return'' + @NewLineChar

    SET @sqlcmd = @sqlcmd +''end''

    /****** Object: Trigger [test_trg] Script Date: 09/08/2011 09:16:31 ******/

    IF NOT EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N''[dbo].[test_trg]''))

    exec (@sqlcmd)',

    @database_name=N'Test',

    @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_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

    You could either schedule the job as it wont do anything unless the trigger is missing or you could create a ddl trigger for table creation on the database as the database (and trigger) will be unaffected by reinitialisation.

    CREATE TRIGGER [db_recreatetriggers]

    ON DATABASE

    FOR CREATE_TABLE

    begin

    exec sp_start_job @job_name = 'ReCreate Triggers'

    end

    go

    Thanks you for this post, that is what my thought too create a job to recreate the triggers but the really good thing heard from you is create a database trigger for create_table....that way I don't need to run this job manually or schedule it. I will go ahead and do it and see how that works.

    [font="Tahoma"]
    --SQLFRNDZ[/url]
    [/font]

Viewing 10 posts - 1 through 9 (of 9 total)

You must be logged in to reply to this topic. Login to reply