web-dev-qa-db-fra.com

Ajouter un article à une publication transactionnelle sans générer de nouvel instantané

En utilisant la réplication transactionnelle SQL 2008 R2 avec des abonnés pull, lorsque nous ajoutons un article, j'aimerais éviter d'avoir à créer un instantané entier (la base de données est ~ 80 Go, donc cela prend des heures).

Depuis cet article , j'ai vu comment faire cela avec un instantané partiel en désactivant immediate_sync, mais cela n'a pas fonctionné pour nous.

Idéalement, j'aimerais simplement l'exécuter dans le cadre de notre script db pour créer la table, donc si nous voulons qu'il soit répliqué, nous le faisons:

Create Table ...    
sp_addArticle ...    
sp_PushThisToOurSubscribersNow    
24
user175528

Vous pouvez ajouter l'article via SSMS à l'aide de l'interface graphique et même lui appliquer des filtres. Tant que vous ne modifiez aucune des autres propriétés de l'article, vous n'aurez pas besoin de générer un instantané complet.

Lorsque vous cliquez sur OK dans l'interface graphique de publication (après avoir ajouté l'article), il se fermera sans inviter à réinitialiser - si cela le fait Invite à réinitialiser, vous avez modifié quelque chose qui nécessite un instantané COMPLET. Si cela se produit, appuyez sur annuler et réessayez.

Après avoir ajouté l'article, vous pouvez simplement démarrer le travail d'instantané et vous remarquerez qu'il ne génère qu'un instantané pour le nouvel article (appelé mini-instantané).

Vérifiez ensuite votre travail de distribution et notez qu'il a créé la table chez l'abonné et copié vos données en bloc.

Bonne chance et faites-moi savoir si vous avez besoin d'aide.

13
NTDLS
  1. Ajouter de nouveaux articles dans la fenêtre de propriétés de votre publication (décochez la case Afficher uniquement les articles cochés dans la liste)
  2. cliquez avec le bouton droit sur le même nœud de publication et accédez à " Afficher l'état de l'agent de capture instantanée "
  3. cliquez sur démarrer et notez simplement le journal dans les mêmes fenêtres qui montre que ce nouvel article est seulement synchronisé
  4. après un court instant, les nouveaux articles seront synchronisés dans les abonnés sans avoir à initialiser tous les articles précédemment synchronisés

enter image description here

8
Iman Abidi

J'avais la même question, et même si je suis DBA depuis un certain temps, je n'ai pas vraiment traité la réplication suffisamment profondément pour être complètement à l'aise, donc j'ai pensé que les ressources et les guides suivants étaient utiles:

  • Ce blog , qui a fourni un bon aperçu du processus. Cela nous rappelle également que, si vous avez une grande publication existante, et que son option est définie sur "immediate_sync", cela entraînera la préparation d'un instantané entièrement nouveau à chaque fois que vous ajoutez ou modifiez un article. Il a donc une astuce pratique pour changer cette option, en utilisant sp_changePublication @publication='MyPub', @property='immediate_sync', @value='false';

  • article de blog MSDN dans "repltalk" (sonne comme une bonne ressource en général!) - pas directement "directement" mais néanmoins utile

  • Cette question, où @ Brandon-Williams a souligné que, s'il s'agit d'un abonnement Pull , vous devez également le rafraîchir en utilisant sp_refreshSubscriptions @publication = 'MyPub'

  • Moniteur de réplication SSMS - moyen pratique d'arrêter et de démarrer les agents (instantané, lecteur de journal) lorsque vous suivez le guide.

Voici les étapes réelles que j'ai suivies, qui ont bien fonctionné et ont rencontré l'approbation de mon DBA superviseur:

  1. Ouvrez le moniteur de réplication, sélectionnez la publication, accédez à Agents, cliquez avec le bouton droit sur Agent du lecteur de journal, cliquez sur Arrêter.
  2. Définissez la publication sur interdire la synchronisation anonyme et non immédiate, à l'aide de sp_changePublication - oui, comme le souligne @cody_konior, c'est sous-documenté, mais cela a bien fonctionné dans mon cas. YMMV
  3. Création manuelle de la table chez l'abonné à l'aide d'un script, remplie de données à l'aide d'une requête de serveur lié (car elle était petite). Vous pouvez également utiliser SSIS, BCP ou tout autre moyen de le faire. Et cela peut ne pas être nécessaire, si vous êtes d'accord avec le snapshot de repl le faire pour vous. Je voulais juste le préparer manuellement la première fois.
  4. Ajoutez l'article (tableau) à l'aide de sp_addArticle
  5. Ajoutez toutes les colonnes du tableau à l'aide de sp_articleColumn (publication et article spécifiés, N'A PAS précisé les colonnes -> implique TOUTES les colonnes)
  6. Exécuté sp_refreshSubscriptions pour que cette publication rafraîchisse l'extracteur
  7. Ouvrez à nouveau le moniteur de réplication, sélectionnez le pub, accédez à Agents, cliquez avec le bouton droit sur Snapshot Agent, cliquez sur "Démarrer". Il s'exécutera une fois, créant le nouvel instantané.
  8. Cliquez avec le bouton droit sur Agent du lecteur de journal, cliquez sur "Démarrer". Il démarrera et continuera de fonctionner normalement, et votre réplication devrait maintenant fonctionner à nouveau.

Et bien que oui, vous pourriez faire la plupart des changements avec l'interface graphique SSMS, je trouve utile de tout écrire afin qu'il puisse être A) sous contrôle de source (change-control), et B) déployés à plusieurs reprises ou sur plusieurs instances. Malheureusement, je n'ai pas passé de temps à écrire les arrêts/démarrages de l'agent, mais cela ne devrait pas être trop difficile étant donné qu'il ne s'agit que de tâches d'agent SQL. Il vous suffit de faire cette astuce "trouver le JobID en utilisant le Job-Name" (requête sysjobs - vraiment, MS?) ...

J'espère que cela aidera les futurs lecteurs!

3
NateJ

Comme indiqué dans Ajout et suppression d'articles dans des publications existantes , vous devez * créer un nouvel instantané pour la publication.

Pour éviter de générer un instantané pour tous les articles lors de l'ajout d'un nouvel article, la propriété de publication immediate_sync doit être défini sur 0. Appelez sp_addarticle, puis sp_addsubscription. Si les abonnements sont extraits, vous devez également appeler sp_refreshsubscriptions. Générez ensuite un instantané et seul un instantané pour le nouvel article ajouté sera généré.

* Il s'agit de l'approche recommandée dans la documentation en ligne de SQL Server. Le problème avec votre approche est qu'elle est sujette à des erreurs.

3
Brandon Williams

Modification majeure Il s'agit d'une réécriture complète de cette réponse (en tenant compte des critiques valables selon lesquelles la version précédente était sujette aux erreurs et causerait des problèmes)

A également publié une démonstration de la façon d'appliquer cela à: Youtube - Réplication SQL Server: Comment ajouter un article sans prendre un instantané .

IMPORTANT: Ceci est [~ # ~] pas [~ # ~] une approche recommandée par Microsoft, donc vous serez seul pour le faire fonctionner, faites [~ # ~] pas [~ # ~] appliquer directement à votre environnement de production sans tests isolés significatifs et vous familiariser avec les étapes!

Étapes à suivre:

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)

Vérifier:

  • effectuer l'insertion sur l'éditeur - vérifier que la ligne arrive sur l'abonné
  • effectuer une mise à jour sur l'éditeur - vérifier que le changement arrive sur l'abonné
  • effectuer la suppression sur l'éditeur - vérifier la ligne supprimée sur l'abonné
  • vérifier que les n dernières lignes sont arrivées et correspondre entre l'éditeur et l'abonné

EXEMPLE Processus

A) Créez vous-même un tableau sur votre éditeur:

/* 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) Créez vous-même un travail/proc/script pour effectuer des insertions/mises à jour/suppressions sur [TableNotUsingSnap] (vous pouvez ensuite l'utiliser pour valider la synchronisation correcte de l'abonné à l'aide de cette méthode.

Pré-étapes:

1. Créez votre table sur l'abonné

/* 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. Créez vos procédures stockées de réplication (mise à jour/insertion/suppression) - sur l'abonné

Vous pouvez créer les proc de repl:

  • Manuellement (attention car il est très facile de se tromper!)
  • Ajoutez l'article à l'aide de la méthode MS Snapshot sur une machine Dev et scriptez les proc de repl (prêt pour que vous ajoutiez vos réglages)
  • Créer/trouver une sorte de générateur

Le changement que vous devrez appliquer:

  • sp_MSinsIF NOT EXISTS (SELECT 'row already exists' FROM [Schema].[TableName] dest WITH (NOLOCK) WHERE dest.Id = @c1) pour ne pas insérer s'il est déjà là
  • sp_MSupd_ [Schema] [TableName] - Mettez en commentaire le IF @@rowcount = 0 ... exec sp_MSreplraiserror ... pour ignorer une mise à jour qui n'est pas appliquée (car l'enregistrement peut avoir été supprimé sur l'éditeur avant de synchroniser les données)
  • sp_MSdel_ [Schema] [TableName] - Mettez en commentaire le IF @@rowcount = 0 ... exec sp_MSreplraiserror ... pour ignorer une suppression qui n'est pas appliquée (car l'enregistrement peut avoir été supprimé sur l'éditeur avant de synchroniser les données)

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

ÉTAPES DE DÉPLOIEMENT

3. Arrêter l'agent de distribution - Sur le distributeur (push) ou l'abonné (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. Ajoutez maintenant l'article à la publication - Sur l'éditeur

Paramètres clés:

  • sp_addarticle - @pre_creation_cmd = N'none' Utilisé pour dire à l'agent de distribution de ne pas supprimer et de générer ses propres objets
  • sp_addsubscription - @sync_type = N'none' Utilisé pour indiquer au Distributeur qu'il n'a pas besoin de créer un nouvel instantané, il peut simplement mettre en file d'attente les commandes du 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. Synchronisez vos données sur

Maintenant, vous devez copier vos données sur votre abonné, vous pouvez:

  • Créer un serveur lié et le copier sur
  • Utilisez l'assistant d'exportation/importation
  • Restaurer une sauvegarde et appliquer des différences
  • Extraire le tableau à l'aide de SSMS Toolpack "Générer des instructions d'insertion ..."

La méthode exacte que vous utilisez, je la laisse au lecteur, cela dépendra également de la durée pendant laquelle vous êtes prêt à faire arrêter votre agent de distribution.

EXTRA: Comme étape supplémentaire dans vos tests, voici un bon endroit pour exécuter votre script (à partir de l'étape (B)) pour créer des actions de DIU sur [ TableNotUsingSnap] afin que vous puissiez gagner en confiance dans cette méthode.

6. Redémarrez l'agent de distribution - Sur le distributeur (push) ou l'abonné (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!
*/
2
Andrew Bickerton