Agregar artículo a publicación transaccional sin generar nueva instantánea

23

Al usar la replicación transaccional SQL 2008 R2 con suscriptores de extracción, cuando agregamos un artículo, me gustaría evitar tener que crear una instantánea completa (la base de datos es de ~ 80 GB, por lo que esto lleva horas).

De este artículo , he visto cómo hacer esto con una instantánea parcial al desactivar la sincronización inmediata, pero eso no funcionó para nosotros.

Idealmente, me gustaría ejecutar esto como parte de nuestro script db para crear la tabla, por lo que si queremos que se replique lo hacemos:

Create Table ...    
sp_addArticle ...    
sp_PushThisToOurSubscribersNow    
usuario175528
fuente

Respuestas:

13

Puede agregar el artículo a través de SSMS utilizando la GUI e incluso aplicarle filtros. Mientras no cambie ninguna de las otras propiedades del artículo, no necesitará generar una instantánea completa.

Al llegar a OK en la GUI de publicación (después de añadir el artículo), se cerrará sin preguntar para reinicializar - si se hace rápido para reiniciar, luego de haber cambiado algo que requiere una instantánea de todo. Si eso sucede, presione cancelar e intente nuevamente.

Después de agregar el artículo, simplemente puede iniciar el trabajo de instantánea y notará que solo genera una instantánea para el nuevo artículo (llamada mini-instantánea).

Luego verifique su trabajo de distribución y observe que creó la tabla en el suscriptor y copió en masa sus datos.

Buena suerte y avíseme si necesita más ayuda.

NTDLS
fuente
Hice todo lo que se explica en esta respuesta, pero todavía me encontraba esperando que toda la base de datos replicada se sincronizara. NO se me solicitó reiniciar después de agregar los nuevos artículos, pero aún así se realizó una inicialización completa. Ten cuidado.
JzInqXc9Dg
7
  1. Agregue nuevos artículos en la ventana de propiedades de su Publicación (desmarque Mostrar solo artículos marcados en la lista)
  2. haga clic con el botón derecho en el mismo nodo de publicación y vaya a " Ver estado del agente de instantáneas "
  3. haga clic en Inicio y solo observe el registro en la misma ventana que muestra que este nuevo artículo solo está sincronizado
  4. poco tiempo después, los nuevos artículos se sincronizarán en suscriptores sin tener que inicializar todos los artículos sincronizados previamente

ingrese la descripción de la imagen aquí

Iman Abidi
fuente
3

Tenía la misma pregunta, y aunque he sido DBA por un tiempo, realmente no he lidiado con la replicación lo suficientemente profundo como para estar completamente cómodo con ella, así que pensé que los siguientes recursos y guías fueron útiles:

  • Este blog , que proporcionó un buen resumen del proceso. También nos recuerda que, si tiene una gran publicación existente, y su opción está configurada en "sincronización_inmediata", hará que se prepare una instantánea completamente nueva cada vez que agregue o cambie un artículo. Entonces tiene un consejo útil para cambiar esa opción, usandosp_changePublication @publication='MyPub', @property='immediate_sync', @value='false';

  • Publicación de blog de MSDN en "repltalk" (¡suena como un buen recurso en general!) - no está "directamente directamente" relacionado pero sigue siendo útil

  • Esta pregunta, donde @ Brandon-Williams señaló que, si se trata de una suscripción Pull , también debe actualizarla, utilizandosp_refreshSubscriptions @publication = 'MyPub'

  • Monitor de replicación SSMS: forma conveniente de detener e iniciar los agentes (instantánea, lector de registro) al seguir la guía.

Estos son los pasos reales que seguí, que funcionaron bien y obtuvieron la aprobación de mi DBA supervisor:

  1. Abra el Monitor de replicación, seleccione la publicación, vaya a Agentes, haga clic con el botón derecho en Log Reader Agent, haga clic en Detener.
  2. Configure la publicación para que no permita la sincronización anónima y no inmediata, usando sp_changePublication- sí, como señala @cody_konior, esto no está documentado, pero funcionó bien en mi caso. YMMV
  3. Creó la tabla en el suscriptor manualmente usando un script, llena de datos usando una consulta de servidor vinculado (ya que era pequeña). También puede usar SSIS, BCP o algún otro medio para hacerlo. Y puede que no sea necesario, si está de acuerdo con que la instantánea de respuesta lo haga por usted. Solo quería prepararlo manualmente la primera vez.
  4. Agregue el artículo (tabla) usando sp_addArticle
  5. Agregue todas las columnas de la tabla usando sp_articleColumn(publicación y artículo especificados, NO especificó columnas -> implica TODAS las columnas)
  6. Ejecutado sp_refreshSubscriptionspara esa publicación para actualizar el pull-er
  7. Abra Replication Monitor nuevamente, seleccione el pub, vaya a Agentes, haga clic con el botón derecho en Snapshot Agent, haga clic en "Inicio". Se ejecutará una vez, creando la nueva instantánea.
  8. Haga clic con el botón derecho en Log Reader Agent, haga clic en "Inicio". Comenzará y continuará ejecutándose normalmente, y su replicación ahora debería estar funcionando nuevamente.

Y aunque sí, podría hacer la mayoría de los cambios con la GUI de SSMS, me parece útil escribir todo para que pueda estar A) bajo control de fuente (control de cambio) y B) implementado repetidamente o en varias instancias . Desafortunadamente, no dediqué tiempo a programar las paradas / inicios del Agente, pero eso no debería ser demasiado difícil dado que solo son Trabajos del Agente SQL. Solo tiene que hacer todo el truco de "encontrar el JobID usando el nombre del trabajo" (consulta sysjobs, ¿en serio, MS?) ...

Espero que ayude a los futuros lectores!

NateJ
fuente
3

Como se señaló en Agregar artículos y eliminar artículos de publicaciones existentes , debe * crear una nueva instantánea para la publicación.

Para evitar generar una instantánea para todos los artículos al agregar un nuevo artículo, la propiedad de publicación immediate_syncdebe establecerse en 0. Llame sp_addarticle, entonces sp_addsubscription. Si las suscripciones son pull, también debe llamar sp_refreshsubscriptions. Luego genere una instantánea y solo se generará una instantánea para el artículo recién agregado.

* Este es el enfoque recomendado en los Libros en pantalla de SQL Server. El problema con su enfoque es que es propenso a errores.

Brandon Williams
fuente
2

Edición principal Esta es una reescritura completa de esta respuesta (teniendo en cuenta las críticas válidas de que la versión anterior era propensa a errores y causaría problemas)

También publicó una demostración de cómo aplicar esto a: Youtube - Replicación de SQL Server: cómo agregar un artículo sin tomar una instantánea .

IMPORTANTE: este NO es un enfoque recomendado por Microsoft, por lo que estará solo con respecto a que funcione, ¡ NO aplique directamente a su entorno de producción sin pruebas aisladas significativas y se sienta cómodo con los pasos!

Pasos 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)

Para verificar:

  • realice la inserción en el editor: verifique que la fila llegue al suscriptor
  • realice la actualización en el editor: verifique que el cambio llegue al suscriptor
  • realizar eliminar en editor: verificar fila eliminada en suscriptor
  • verifique que hayan llegado las últimas n filas y coincida entre el editor y el suscriptor

EJEMPLO Proceso

A) Cree una tabla en su 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) Cree usted mismo un trabajo / proc / script para hacer algunas inserciones / actualizaciones / eliminaciones en [TableNotUsingSnap] (luego puede usar esto para validar cómo el suscriptor se sincroniza correctamente usando este método.

Pre-pasos:

1. Crea tu tabla en el suscriptor

/* 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. Cree sus procedimientos almacenados de replicación (actualizar / insertar / eliminar) - en el suscriptor

Puede crear los procedimientos de respuesta:

  • Manualmente (¡tenga cuidado ya que es muy fácil cometer un error!)
  • Agregue el artículo utilizando el método MS Snapshot en una máquina Dev y realice un script en los procedimientos de respuesta (listo para que agregue sus ajustes)
  • Crear / encontrar algún tipo de generador

El cambio que deberá aplicar:

  • sp_MSins_ [Schema] [TableName] - Agregar IF NOT EXISTS (SELECT 'row already exists' FROM [Schema].[TableName] dest WITH (NOLOCK) WHERE dest.Id = @c1)para no insertar si ya está allí
  • sp_MSupd_ [Esquema] [TableName] - Comenta el IF @@rowcount = 0 ... exec sp_MSreplraiserror ... para ignorar una actualización que no se aplica (ya que el registro puede haberse eliminado en el editor antes de sincronizar los datos)
  • sp_MSdel_ [Schema] [TableName] - Comenta IF @@rowcount = 0 ... exec sp_MSreplraiserror ...para ignorar una eliminación que no se aplica (ya que el registro puede haberse eliminado en el editor antes de sincronizar los datos)

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

PASOS DE DESPLIEGUE

3. Detenga el agente de distribución: en el Distribuidor (Push) o Suscriptor (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. Ahora agregue el artículo a la publicación - En el editor

Parámetros clave:

  • sp_addarticle- se @pre_creation_cmd = N'none'usa para decirle al agente de distribución que no deje caer y genere sus propios objetos
  • sp_addsubscription- @sync_type = N'none'solía decirle a Distributer que no necesita crear una nueva instantánea, solo puede poner en cola los comandos del 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. Sincroniza tus datos

Ahora necesita copiar sus datos a su suscriptor, podría:

  • Cree un servidor vinculado y cópielo
  • Utilice el asistente de exportación / importación
  • Restaurar una copia de seguridad y aplicar diffs
  • Extraiga la tabla con el paquete de herramientas SSMS 'Generar declaraciones de inserción ...'

El método exacto que utilice lo dejo al lector, también dependerá de cuánto tiempo esté dispuesto a detener su Agente de distribución.

EXTRA: Como un paso adicional en sus pruebas, aquí hay un buen lugar para ejecutar su script (desde el Paso (B)) para crear acciones del DIU en [TableNotUsingSnap] para que pueda ganar confianza en este método.

6. Reinicie el agente de distribución: en el Distribuidor (Push) o Suscriptor (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
fuente