Adicionar artigo à publicação transacional sem gerar novo instantâneo

23

Usando a replicação transacional do SQL 2008 R2 com assinantes pull, quando adicionamos um artigo, eu gostaria de evitar a criação de um instantâneo inteiro (o banco de dados é de ~ 80 GB, isso leva horas).

A partir deste artigo , eu vi como fazer isso com um instantâneo parcial definindo immediate_sync fora, mas isso não funcionou para nós.

Idealmente, eu gostaria de executar isso como parte do nosso script db para criar a tabela; portanto, se quisermos replicá-lo, faremos:

Create Table ...    
sp_addArticle ...    
sp_PushThisToOurSubscribersNow    
user175528
fonte

Respostas:

13

Você pode adicionar o artigo através do SSMS usando a GUI e até aplicar filtros a ela. Desde que você não altere nenhuma das outras propriedades do artigo, não será necessário gerar uma captura instantânea completa.

Quando você bate em OK na GUI publicação (depois de adicionar o artigo), que vai fechar sem avisar para reinicializar - se ele faz solicitação para reinicializar, então você mudou algo que requer um instantâneo completo. Se isso acontecer, clique em cancelar e tente novamente.

Depois de adicionar o artigo, você pode simplesmente iniciar o trabalho de captura instantânea e perceberá que ele gera apenas uma captura instantânea para o novo artigo (chamado de mini captura instantânea).

Em seguida, verifique seu trabalho de distribuição e observe que ele criou a tabela no assinante e copiou seus dados em massa.

Boa sorte e avise-me se precisar de mais assistência.

NTDLS
fonte
Fiz tudo o que foi explicado nesta resposta, mas ainda estava esperando a sincronização de todo o banco de dados replicado. NÃO fui solicitado a reinicializar depois de adicionar os novos artigos, mas ele ainda fez uma inicialização completa. Seja cuidadoso.
JzInqXc9Dg 29/03
7
  1. Adicione novos artigos à sua janela de propriedades Publicação (desmarque a opção Mostrar apenas artigos marcados na lista)
  2. clique com o botão direito do mouse no mesmo nó Publicação e vá para " Exibir Status do Snapshot Agent "
  3. clique em Iniciar e observe o log nas mesmas janelas que mostram que este novo artigo é sincronizado apenas
  4. após um curto período de tempo, os novos artigos serão sincronizados nos assinantes sem precisar inicializar todos os sincronizados anteriormente

insira a descrição da imagem aqui

Iman Abidi
fonte
3

Eu tinha a mesma pergunta e, mesmo sendo um DBA há algum tempo, não lidei com a replicação com profundidade suficiente para me sentir completamente confortável com ela, então pensei que os seguintes recursos e guias eram úteis:

  • Este blog , que forneceu um bom esboço do processo. Ele também nos lembra que, se você tiver uma publicação grande e sua opção estiver definida como "Instant_sync", fará com que um instantâneo totalmente novo seja preparado toda vez que você adicionar ou alterar um artigo. Então ele tem uma dica útil para mudar essa opção, usandosp_changePublication @publication='MyPub', @property='immediate_sync', @value='false';

  • Postagem do blog do MSDN em "repltalk" (soa como um bom recurso em geral!) - não "diretamente diretamente", mas ainda sendo útil

  • Esta pergunta, onde @ Brandon-Williams apontou que, se for uma assinatura Pull , você também deve atualizá-la usandosp_refreshSubscriptions @publication = 'MyPub'

  • Monitor de replicação SSMS - maneira conveniente de parar e iniciar os agentes (instantâneo, leitor de log) ao seguir o guia.

Aqui estão as etapas reais que segui, que funcionaram bem e alcançaram a aprovação do meu DBA supervisor:

  1. Abra o Replication Monitor, selecione a publicação, vá para Agentes, clique com o botão direito do mouse em Log Reader Agent, clique em Parar.
  2. Defina a publicação para não permitir a sincronização anônima e não imediata, usando sp_changePublication- yes, como @cody_konior aponta, isso está sub-documentado, mas funcionou bem no meu caso. YMMV
  3. Criou a tabela no assinante manualmente usando o script, preenchido com dados usando a consulta do servidor vinculado (já que era pequeno). Você também pode usar o SSIS, o BCP ou algum outro meio para fazer isso. E pode não ser necessário, se você estiver bem com o repl-snapshot fazendo isso por você. Eu só queria prepará-lo manualmente na primeira vez.
  4. Adicione o artigo (tabela) usando sp_addArticle
  5. Adicione todas as colunas da tabela usando sp_articleColumn(publicação e artigo especificados, NÃO especificar colunas -> implica TODAS as colunas)
  6. Executado sp_refreshSubscriptionspara essa publicação para atualizar o extrator
  7. Abra o Replication Monitor novamente, selecione o pub, vá para Agentes, clique com o botão direito do mouse em Snapshot Agent, clique em "Iniciar". Ele será executado uma vez, criando o novo instantâneo.
  8. Clique com o botão direito do mouse em Log Reader Agent, clique em "Iniciar". Ele começará e continuará sendo executado normalmente, e sua replicação deverá estar funcionando novamente.

E, embora sim, você poderia fazer a maioria das alterações com a GUI do SSMS, acho útil escrever tudo para que possa ser A) sob controle de origem (controle de mudança) e B) implantado repetidamente ou em várias instâncias . Infelizmente, não dediquei tempo ao script do Agente para / inicia, mas isso não deve ser muito difícil, pois são apenas trabalhos do SQL Agent. Você só precisa fazer todo esse truque "encontrar o JobID usando o Job-Name" (consulta sysjobs- realmente, MS?) ...

Espero que ajude futuros leitores!

NateJ
fonte
3

Conforme observado em Adicionando artigos a e descartando artigos de publicações existentes , você deve * criar um novo instantâneo para a publicação.

Para evitar a geração de um instantâneo para todos os artigos ao adicionar um novo artigo, propriedade publicação immediate_syncdeve ser definido como 0. Chamada sp_addarticle, então sp_addsubscription. Se as assinaturas forem recebidas, você também deverá ligar sp_refreshsubscriptions. Em seguida, gere um instantâneo e apenas um instantâneo para o artigo adicionado recentemente será gerado.

* Essa é a abordagem recomendada nos Manuais Online do SQL Server. O problema com sua abordagem é que ela é propensa a erros.

Brandon Williams
fonte
2

Edição principal Esta é uma reescrita completa desta resposta (levando em consideração críticas válidas de que a versão anterior era propensa a erros e causaria problemas)

Também postou uma demonstração de como aplicar isso ao: Youtube - Replicação do SQL Server: como adicionar um artigo sem tirar uma captura instantânea .

IMPORTANTE: Esta NÃO é uma abordagem recomendada da Microsoft; portanto, você estará por conta própria em fazê-lo funcionar. NÃO se aplique diretamente ao seu ambiente de produção sem testes isolados significativos e se familiarize com as etapas!

Passos a seguir:

Planning steps:
    * Choose Publication that article will be added to
    * Gather information about the publication 
        exec sp_helppublication '[Name of Publication]'
        https://msdn.microsoft.com/en-us/library/ms189782(v=sql.105).aspx
        - replication frequency = 0 - this is Transactional replication (THIS IS A REQUIREMENT FOR THIS METHOD)
        - replicate_ddl = 1 - means ALTER TABLES will apply SQL Server generated repl procs
        - independent_agent = 1 - means that you will only affect tables in this publication when deploying
    * Identify which subscribers are going to be affected

Pre-deployment steps (can be done at any time)
    1. Create table on subscribers
    2. Create custom replication procs on subscribers
       (Customisation will ignore if the IUD has already been applied to subscriber - because you have manually sync'd the data)

Deployment/Potential impact:
    3. Stop Distribution Agents to all subscribers for this publication
    4. Add article to publication on publisher
    5. Sync data from publisher to subscriber
    6. Start Distribution Agents to all subscribers for this publication
    7. Monitor/Verify all data has arrived

Optional follow on:
    8. Apply standard repl procs (removing if not exists checks)
       This is optional as the generated repl scripts should be fine for the most part

Note:  When ALTER table scripts are applied on the Publisher (when replicate_ddl = 1) repl procs will automatically be recreated by the Distribution Agent (so any customisation will be lost)

Verificar:

  • executar inserção no editor - verifique se a linha chega ao assinante
  • executar atualização no editor - verifique se a alteração chega no assinante
  • executar exclusão no editor - verifique a linha excluída no assinante
  • verifique se as últimas n linhas chegaram e correspondem entre o editor e o assinante

EXEMPLO Processo

A) Crie uma tabela para seu editor:

/* Deliberately applying IDENTITY, DEFAULT & INDEX to demonstrate usage on subscriber */
CREATE TABLE [dbo].[TableNotUsingSnap](
    [Id] [int] NOT NULL IDENTITY(1,1),
    [Note_Text] [varchar](4096) NOT NULL,
    [CreatedDate] [datetime] NULL,
    [LoggedDate] [datetime] NOT NULL CONSTRAINT DF_TableNotUsingSnap_LoggedDate DEFAUlT GETUTCDATE(),
 CONSTRAINT [PK_TableNotUsingSnap] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO 

CREATE NONCLUSTERED INDEX [IDX_NC_TableNotUsingSnap_LoggedDate]  ON [dbo].[TableNotUsingSnap]
(
    [LoggedDate] ASC
) INCLUDE ([Note_Text])
GO

B) Crie um job / proc / script para fazer algumas inserções / atualizações / exclusões em [TableNotUsingSnap] (você pode usá-lo para validar como o assinante é sincronizado corretamente usando esse método.

Pré-etapas:

1. Crie sua tabela no assinante

/* example script to add a table to a publication without running the snapshot agent 
Steps: 
    Pre steps: 
    1. Create table on subscribers
    2. Create replication procs on subscribers

    Deployment/Potential impact:
    3. Stop Distribution Agents to all subscribers for this publication
    4. Add article to publication on publisher
    5. DTS data from publisher to subscriber
    6. Start Distribution Agents to all subscribers for this publication
    7. Monitor/Verify all data has arrived

=========================================================
Notes:
    * Drop unnecessary FK's, Indexes
    * Do NOT have IDENTITY(1,1), DEFAULTS
    * Do have a Clustered PK
    * Create appropriate indexes for your subscribers use case */ 

-- RUN ON SUBSCRIBER
IF OBJECT_ID('dbo.TableNotUsingSnap') IS NOT NULL
    exec sp_rename 'dbo.TableNotUsingSnap', 'TableNotUsingSnap_20170127'
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[TableNotUsingSnap](
    [Id] [int] NOT NULL,
    [Note_Text] [varchar](4096) NOT NULL,
    [CreatedDate] [datetime] NULL,
    [LoggedDate] [datetime] NOT NULL,
 CONSTRAINT [PK_TableNotUsingSnap] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

2. Crie seus procedimentos armazenados de replicação (atualização / inserção / exclusão) - no Assinante

Você pode criar os procs de repl:

  • Manualmente (tenha cuidado, pois é muito fácil cometer um erro!)
  • Adicione o artigo usando o método MS Snapshot em uma máquina Dev e faça o script dos procs de repl (pronto para você adicionar seus ajustes)
  • Criar / Encontrar algum tipo de gerador

A alteração que você precisará aplicar:

  • sp_MSins_ [Schema] [TableName] - Adicione IF NOT EXISTS (SELECT 'row already exists' FROM [Schema].[TableName] dest WITH (NOLOCK) WHERE dest.Id = @c1)para não inserir se já estiver lá
  • sp_MSupd_ [Schema] [TableName] - comente IF @@rowcount = 0 ... exec sp_MSreplraiserror ...para ignorar uma atualização que não é aplicada (pois o registro pode ter sido excluído no editor antes de você sincronizar os dados)
  • sp_MSdel_ [Schema] [TableName] - comente IF @@rowcount = 0 ... exec sp_MSreplraiserror ...para ignorar uma exclusão que não é aplicada (como o registro pode ter sido excluído no editor antes de você sincronizar os dados)

sp_MSins_dboTableNotUsingSnap:

/* Customised Replication insert proc utilized to support adding to replication without a snapshot. */
create procedure [dbo].[sp_MSins_dboTableNotUsingSnap]     
    @c1 int,     
    @c2 varchar(4096),     
    @c3 datetime
AS 
BEGIN
    IF NOT EXISTS (SELECT 'row already exists' FROM [dbo].[TableNotUsingSnap] dest WITH (NOLOCK) WHERE dest.Id = @c1)
    BEGIN
        insert into [dbo].[TableNotUsingSnap]
            ([Id],
            [Note_Text],
            [Repl_Upsert_UTC]) 
        values 
            (@c1,
            @c2,
            @c3)  
    END
END
GO

sp_MSupd_dboTableNotUsingSnap:

/* Customised Replication insert proc utilized to support adding to replication without a snapshot. */
create procedure [dbo].[sp_MSupd_dboTableNotUsingSnap]     
    @c1 int = NULL,     
    @c2 varchar(4096) = NULL,     
    @c3 datetime = NULL, 
    @pkc1 int = NULL, 
    @bitmap binary(1)
AS 
BEGIN
    declare @primarykey_text nvarchar(100) = '' 

    if (substring(@bitmap,1,1) & 1 = 1)
    begin 
        update [dbo].[TableNotUsingSnap]
        set [Id] = case substring(@bitmap,1,1) & 1 when 1 then @c1 else [Id] end, 
            [Note_Text] = case substring(@bitmap,1,1) & 2 when 2 then @c2 else [Note_Text] end,
            [Repl_Upsert_UTC] = case substring(@bitmap,1,1) & 4 when 4 then @c3 else [Repl_Upsert_UTC] END
        WHERE [Id] = @pkc1

        /*  Commented out while adding to publication
        if @@rowcount = 0
            if @@microsoftversion>0x07320000
            Begin
                set @primarykey_text = @primarykey_text + '[id] = ' + convert(nvarchar(100),@pkc1,1)
                exec sp_MSreplraiserror @errorid=20598, @param1=N'[dbo].[TableNotUsingSnap]', @param2=@primarykey_text, @param3=13233
            End */
    END
    ELSE
    BEGIN
        update [dbo].[TableNotUsingSnap]
        set [Note_Text] = case substring(@bitmap,1,1) & 2 when 2 then @c2 else [Note_Text] end,
            [Repl_Upsert_UTC] = case substring(@bitmap,1,1) & 4 when 4 then @c3 else [Repl_Upsert_UTC] END
        WHERE [Id] = @pkc1

        /*  Commented out while adding to publication
        if @@rowcount = 0
            if @@microsoftversion>0x07320000
            Begin
                set @primarykey_text = @primarykey_text + '[id] = ' + convert(nvarchar(100),@pkc1,1)
                exec sp_MSreplraiserror @errorid=20598, @param1=N'[dbo].[TableNotUsingSnap]', @param2=@primarykey_text, @param3=13233
            End */
    end
END
GO

sp_MSdel_dboTableNotUsingSnap:

/* Customised Replication insert proc utilized to support adding to replication without a snapshot. */
create procedure [dbo].[sp_MSdel_dboTableNotUsingSnap]
    @pkc1 int
as
begin  
    declare @primarykey_text nvarchar(100) = ''

    delete [dbo].[TableNotUsingSnap]
    where [Id] = @pkc1

    /* ignore if the record doesn't exist when deleting it 
    if @@rowcount = 0
        if @@microsoftversion>0x07320000
        Begin
            set @primarykey_text = @primarykey_text + '[Id] = ' + convert(nvarchar(100),@pkc1,1)
            exec sp_MSreplraiserror @errorid=20598, @param1=N'[dbo].[TableNotUsingSnap]', @param2=@primarykey_text, @param3=13234
        End */
end
GO

ETAPAS DE IMPLANTAÇÃO

3. Pare o agente de distribuição - No distribuidor (push) ou no assinante (pull)

/*  example script to add a table to a publication without running the snapshot agent
    Steps:
        Pre steps:
        1. Create table on subscribers
        2. Create replication procs on subscribers

        Deployment/Potential impact:
    **  3. Stop Distribution Agents to all subscribers for this publication
        4. Add article to publication on publisher
        5. DTS data from publisher to subscriber
        6. Start Distribution Agents to all subscribers for this publication
        7. Monitor/Verify all data has arrived

    =========================================================
    Note: check your publication settings:
          if @independent_agent = N'false'
            you will need to stop the distribution agent which will affect ALL
            publications going to that subscriber

          if @independent_agent = N'true'
            you will need to stop the publication specific distribution agent 
            (to each subscriber)

          Plan your live release around that knowledge!
*/

-- IF PUSH REPLICATION: RUN ON DISTRIBUTION SERVER
-- IF PULL REPLICATION: RUN ON SUBSCRIBER SERVER

/* disable the Job first */
exec msdb..sp_update_job @job_name = '[Distribution agent job]', @enabled = 0
GO

/* wait for 10 seconds - precaution ONLY */
WAITFOR DELAY '00:00:10.000'
GO

/* now stop the job */
exec msdb..sp_stop_job @job_name = '[Distribution agent job]'
GO

/* 
    NOTE: You might recieve an error about stopping a job that is already stopped.  You can ignore that error.
                It is up to you to verify that the job has been stopped correctly!
*/

4. Agora adicione o artigo à publicação - No Publicador

Parâmetros principais:

  • sp_addarticle- @pre_creation_cmd = N'none'usado para dizer ao Agente de distribuição para não deixar cair e gerar seus próprios objetos
  • sp_addsubscription- @sync_type = N'none'usado para dizer ao Distribuidor que ele não precisa criar um novo instantâneo, ele pode apenas enfileirar os comandos do DIU

sp_addarticle:

exec sp_addarticle 
    @publication = N'Publication Name',
    @article = N'TableNotUsingSnap',
    @source_owner = N'dbo',
    @source_object = N'TableNotUsingSnap',
    @type = N'logbased',
    @description = N'',
    @creation_script = N'',
    @pre_creation_cmd = N'none',        /* this is a critical flag - tells SQL Server to not drop/recreate the repl procs/object on the subscriber */
    @schema_option = 0x0000000008004093,
    @identityrangemanagementoption = N'none',
    @destination_table = N'TableNotUsingSnap',
    @destination_owner = N'dbo',
    @status = 16,
    @vertical_partition = N'false',
    @ins_cmd = N'CALL [sp_MSins_dboTableNotUsingSnap]',
    @del_cmd = N'CALL [sp_MSdel_dboTableNotUsingSnap]',
    @upd_cmd = N'SCALL [sp_MSupd_dboTableNotUsingSnap]'
GO

-- Adding the transactional subscriptions
exec sp_addsubscription @publication = N'Publication Name',
    @subscriber = N'Subscriber Server',
    @destination_db = N'Subscriber DB',
    @subscription_type = N'Push',
    @sync_type = N'none',               /* tell SQL Server not to sync/snapshot this change to the publication */
    @article = N'all',
    @update_mode = N'read only',
    @subscriber_type = 0
GO

5. Sincronize seus dados

Agora você precisa copiar seus dados para o assinante, você pode:

  • Crie um servidor vinculado e copie-o
  • Use o Assistente de Exportação / Importação
  • Restaurar um backup e aplicar diffs
  • Extraia a tabela usando o SSMS Toolpack 'Generate Insert Statements ...'

O método exato que você usar eu deixo para o leitor, também dependerá de quanto tempo você estiver disposto a parar o seu Agente de Distribuição.

EXTRA: Como uma etapa adicional em seus testes, aqui está um bom local para executar seu script (da Etapa (B)) para criar ações de DIU em [TableNotUsingSnap] para que você possa ganhar confiança nesse método.

6. Reinicie o agente de distribuição - No Distribuidor (Push) ou Assinante (Pull)

/*  example script to add a table to a publication without running the snapshot agent
    Steps:
        Pre steps:
        1. Create table on subscribers
        2. Create replication procs on subscribers

        Deployment/Potential impact:
        3. Stop Distribution Agents to all subscribers for this publication
        4. Add article to publication on publisher
        5. DTS data from publisher to subscriber
    **  6. Start Distribution Agents to all subscribers for this publication
        7. Monitor/Verify all data has arrived

    =========================================================
    Note: check your publication settings:
          if @independent_agent = N'false'
            you will need to stop the distribution agent which will affect ALL
            publications going to that subscriber

          if @independent_agent = N'true'
            you will need to stop the publication specific distribution agent 
            (to each subscriber)

          Plan your live release around that knowledge!
*/

-- IF PUSH REPLICATION: RUN ON DISTRIBUTION SERVER
-- IF PULL REPLICATION: RUN ON SUBSCRIBER SERVER

/* disable the Job first */
exec msdb..sp_update_job @job_name = 'Distribution agent job', @enabled = 1
GO

/* wait for 10 seconds - precaution ONLY */
WAITFOR DELAY '00:00:10.000'
GO

/* now stop the job */
exec msdb..sp_start_job @job_name = 'Distribution agent job'
GO

/* 
    Now go and make sure everything is working ok!
*/
Andrew Bickerton
fonte