web-dev-qa-db-fra.com

Comment réparer une réplication foirée sur MS SQL Server

J'ai restauré une base de données à partir d'une sauvegarde. La base de données utilise la réplication pour publier sur un autre serveur. En supposant que la restauration de la base de données interromprait la réplication, j'ai essayé de supprimer la réplication et de la recréer (nous avons un script pour la recréer à partir de zéro). Je ne sais pas exactement ce que j'ai fait, mais maintenant il est dans un état complètement foiré et je ne peux pas le réparer.

Tout d'abord, j'essaie de me débarrasser de l'abonnement (sur le serveur éditeur):

EXEC sp_dropsubscription @publication = 'PublicationName', @article = N'all', @subscriber = 'SubscriberServerName'

Cela semble fonctionner. SELECT * FROM syssubscriptions ne montre aucun résultat. En regardant sur le serveur d'abonné, SSMS> {SubscriberServer}> Réplication> Abonnements locaux - l'abonnement n'est pas là.

Alors j'essaie de supprimer la publication. SSMS> {Server}> Réplication> Publications locales> {PublicationName}> Supprimer. Cela donne le message d'erreur suivant:

Could not delete publication 'PublicationName'.
Could not drop article. A subscription exists on it.
Changed database context to 'DatabaseName'. (Microsoft SQL Server, Error: 14046)

Ok, donc j'essaye de laisser tomber les articles:

EXEC sp_droparticle @publication = 'PublicationName', @article = N'all'

et obtenez cette erreur:

Invalidated the existing snapshot of the publication. Run the Snapshot Agent again to generate a new snapshot.
Msg 14046, Level 16, State 1, Procedure sp_MSdrop_article, Line 75
Could not drop article. A subscription exists on it.

Ok, donc j'essaie de démarrer l'agent Snapshot et j'obtiens cette exception SQL interne:

The SQL command 'sp_MSactivate_auto_sub' had returned fewer rows than expected by the replication agent.

J'ai donc essayé une autre méthode pour supprimer l'article, DELETE FROM sysarticles. Cela semble avoir fonctionné - je me suis maintenant débarrassé des articles, mais j'obtiens toujours la même erreur "Impossible de supprimer la publication car il existe au moins un abonnement pour cette publication" lorsque j'essaie de supprimer la publication.

J'ai également redémarré SQL Server - n'a pas aidé.

Je ne sais pas ce qui se passe ici et comment puis-je y remédier?

BTW c'est ce qui se passe lorsque vous donnez à un développeur de logiciels qui en sait juste assez pour être dangereux les clés de la base de données. Heureusement, ce n'est pas un environnement de production ...

11
TallGuy

TLDR:

Il semble que la désactivation et la réactivation de la réplication aient probablement résolu le problème:

exec sp_replicationdboption @dbname = N'DatabaseName', @optname = N'publish', @value = N'false'
exec sp_replicationdboption @dbname = N'DatabaseName', @optname = N'publish', @value = N'true'

Je suppose que c'est l'équivalent de l'éteindre puis de le rallumer ...

Version plus longue:

Un collègue a essayé de le réparer. Il a essayé quelques choses mais n'est pas allé très loin. Le seul changement qu'il a fait avant d'abandonner était de désactiver la réplication.

J'ai ensuite essayé suggestion de Cody . La commande sp_dropsubscription s'est plainte qu'aucun abonnement n'existe. J'ai donc essayé la commande sp_droppublication. Cela s'est plaint que la réplication n'était pas activée sur la base de données. Je l'ai donc activé et relancé la commande. Cette fois, il s'est plaint que la publication n'existait pas. J'ai actualisé le nœud des publications locales dans SSMS et bien sûr qu'il avait disparu. J'ai exécuté le script de configuration de la réplication, généré un nouvel instantané et tout fonctionne maintenant correctement. Joie!

Je ne suis pas sûr à 100% que la désactivation et l'activation de la réplication soient ce qui a réellement résolu le problème, mais cela vaut vraiment la peine d'essayer si la réplication est gâchée.

10
TallGuy

J'ai eu un problème avec la réplication et l'ai résolu avec ce

DECLARE @subscriptionDB AS sysname
SET @subscriptionDB = N'DBName'

-- Remove replication objects from a subscription database (if necessary).
USE master
EXEC sp_removedbreplication @subscriptionDB
GO 

Cela et:

exec sp_cleanupdbreplication

Sont les sauveurs lors du nettoyage des réplications en désordre.

5
Guillermo Zooby

La restauration de la base de données interrompt la réplication, c'est donc normal. De plus, la plupart des autres messages d'erreur ne sont que des suivis car vous n'avez pas pu supprimer tous les abonnements (ou du moins SQL le pense).

Vous savez que vous avez votre éditeur (la base de données source), et au moins un abonné (la base de données de destination), et qu'il s'agit de deux serveurs différents. Je veux juste mentionner qu'il y a aussi un distributeur qui se trouve sur l'un ou l'autre de ces serveurs, et probablement dans une base de données nommée distribution. Parfois, il contient des informations utiles et parfois les choses tombent parce que les informations entre les trois ne correspondent pas.

Quoi qu'il en soit, lorsque vous avez vérifié les abonnés, avez-vous également vérifié cette section sur le serveur éditeur pour vous assurer qu'il n'y avait rien d'autre dans la liste? Si vous en trouvez, vous pouvez essayer de le supprimer manuellement:

exec sp_dropsubscription @publication = N'xxx', @subscriber = N'xxx', @destination_db = N'xxx', @article = N'all'
-- And if that doesn't work
exec sp_dropsubscription @publication = N'xxx', @subscriber = N'xxx', @destination_db = N'xxx', @article = N'all', @Ignore_Distributor = 1

Mais en supposant qu'ils ont vraiment disparu, essayez ceci sur la base de données de l'éditeur:

exec sp_droppublication @publication = N'xxx'
-- And if that doesn't work
exec sp_droppublication @publication = N'xxx', @Ignore_Distributor = 1

Tiens nous au courant de comment ça se passe. La réplication quand elle entre dans cet état me confond, moi et les autres bons DBA, rien à voir avec le fait d'être développeur :-)

2
Cody Konior

La seule façon dont j'ai pu me débarrasser des artefacts de réplication fantôme est de supprimer les abonnements, les articles et les publications. S'il existe toujours des abonnements fantômes, recréez la publication, y compris l'abonné fantôme. Cela semble fonctionner avec les anciennes versions en particulier.

0

c'est ce que je fais normalement quand j'ai une publication qui est foirée.

c'est un peu moche mais ça a fonctionné pour moi à plusieurs reprises sur des environnements différents. quelles sont les causes? c'est parfois difficile à comprendre, le mieux est parfois de recommencer à zéro, mais même pour cela, vous devez supprimer all le residuals de la publication actuelle qui est défectueux.

juste pour le mettre en contexte:

Voici ce que je vois du moniteur de réplication:

enter image description here

et quand j'utilise mon propre moniteur de réplication utilisant T-SQL :

DECLARE @cmd NVARCHAR(max)
DECLARE @publisher SYSNAME, @publisher_db SYSNAME, @publication SYSNAME, @pubtype INT
DECLARE @subscriber SYSNAME, @subscriber_db SYSNAME, @subtype INT
DECLARE @cmdcount INT, @processtime INT
DECLARE @ParmDefinition NVARCHAR(500)
DECLARE @JobName SYSNAME
DECLARE @minutes INT, @threshold INT, @maxCommands INT, @mail CHAR(1) = 'N'
SET @minutes = 60 --> Define how many minutes latency before you would like to be notified
SET @maxCommands = 80000  --->  change this to represent the max number of outstanding commands to be proceduresed before notification
SET @threshold = @minutes * 60

IF OBJECT_ID ('TEMPDB..#Replication_Qu_History')  IS NOT NULL
   DROP TABLE #Replication_Qu_History

IF OBJECT_ID ('TEMPDB..##PublicationInfo')  IS NOT NULL
   DROP TABLE  ##PublicationInfo

IF OBJECT_ID ('TEMPDB..#PublisherInfo')  IS NOT NULL
   DROP TABLE  #PublisherInfo

IF OBJECT_ID ('TEMPDB..##SubscriptionInfo')  IS NOT NULL
   DROP TABLE  ##SubscriptionInfo

SELECT * INTO #PublisherInfo
FROM OPENROWSET('SQLOLEDB', 'SERVER=(LOCAL);TRUSTED_CONNECTION=YES;'
, 'SET FMTONLY OFF EXEC distribution.dbo.sp_replmonitorhelppublisher')

SELECT @publisher = publisher FROM #PublisherInfo     

SET @cmd = 'SELECT * INTO ##PublicationInfo FROM OPENROWSET(''SQLOLEDB'',''SERVER=(LOCAL);TRUSTED_CONNECTION=YES''
,''SET FMTONLY OFF EXEC distribution.dbo.sp_replmonitorhelppublication @publisher='
+ @publisher + ''')'
--select @cmd
EXEC sp_executesql @cmd

SELECT @publisher_db=publisher_db, @publication=publication, @pubtype=publication_type  FROM ##PublicationInfo

SET @cmd = 'SELECT * INTO ##SubscriptionInfo FROM OPENROWSET(''SQLOLEDB'',''SERVER=(LOCAL);TRUSTED_CONNECTION=YES''
,''SET FMTONLY OFF EXEC distribution.dbo.sp_replmonitorhelpsubscription @publisher='
+ @publisher + ',@publication_type=' + CONVERT(CHAR(1),@pubtype) + ''')'
--select @cmd
EXEC sp_executesql @cmd


ALTER TABLE ##SubscriptionInfo
ADD  PendingCmdCount INT NULL,
EstimatedProcessTime INT NULL


SELECT *
FROM #PublisherInfo

SELECT *
FROM ##SubscriptionInfo 

SELECT *
FROM ##PublicationInfo 

vous pouvez voir 2 lignes sur la dernière case ci-dessous - et l'une d'entre elles ne devrait pas être là:

enter image description here

la même chose lorsque j'utilise ce script:

EXEC distribution.dbo.sp_replmonitorhelppublication @publisher='my publisher'

enter image description here

D'abord, vous faites ce qui est montré dans l'autre réponses ci-dessus, si cela fonctionne , c'est bien, cela fonctionne parfois, problème résolu.

ce serait plus ou moins ça:

exec master.dbo.sp_replicationdboption @dbname = 'my_PUBLICATION', @optname = N'publish', @value = N'false'
exec master.dbo.sp_replicationdboption @dbname = 'my_PUBLICATION', @optname = N'publish', @value = N'true'

sp_droppublication @publication='my_PUBLICATION'

-- Remove replication objects from a subscription database (if necessary).
exec master.dbo.sp_removedbreplication 'my_PUBLICATION'

exec master.dbo.sp_removedbreplication 'my_PUBLICATION'

use my_PUBLICATION

sp_removedbreplication @type='both'


USE [master]
EXEC sp_replicationdboption 
  @dbname = N'my_PUBLICATION', 
  @optname = N'publish', 
  @value = N'false';
GO


EXEC distribution.dbo.sp_replmonitorhelppublication @publisher='PUBLISHER_SERVER'

sp_replmonitorhelppublisher @publisher='PUBLISHER_SERVER'

DECLARE @publicationDB AS sysname;
DECLARE @publication AS sysname;
SET @publicationDB = N'my_PUBLICATION'; 
SET @publication = N'my_PUBLICATION'; 

-- Remove a transactional publication.
USE my_PUBLICATION
EXEC sp_droppublication @publication = @publication;

-- Remove replication objects from the database.
USE [master]
EXEC sp_replicationdboption 
  @dbname = @publicationDB, 
  @optname = N'publish', 
  @value = N'false';
GO

Maintenant, pour nous débarrasser complètement de cette publication, nous allons commencer par nous connecter au buscriber, puis à l'éditeur, puis au distributeur selon le script ci-dessous:

-- Connect Subscriber
:connect [SUBSCRIBER_SERVER]
use [master]
exec sp_helpreplicationdboption @dbname = N'SUBSCRIBER_DATABASE'
go
use [SUBSCRIBER_DATABASE]
exec sp_subscription_cleanup @publisher = N'PUBLISHER_SERVER', @publisher_db = N'my_PUBLICATION_DB', 
@publication = N'my_PUBLICATION'
go


-- Connect Publisher Server
:connect [PUBLISHER_SERVER]
-- Drop Subscription
use [my_PUBLICATION]
exec sp_dropsubscription @publication = N'my_PUBLICATION', @subscriber = N'all', 
@destination_db = N'SUBSCRIBER_DATABASE', @article = N'all'
go
-- Drop publication
exec sp_droppublication @publication = N'my_PUBLICATION'
-- Disable replication db option
exec sp_replicationdboption @dbname = N'my_PUBLICATION_db', @optname = N'publish', @value = N'false'
GO

-- Connect Distributor
:CONNECT [PUBLISHER_SERVER]
go

exec Distribution.dbo.sp_MSremove_published_jobs @server = 'PUBLISHER_SERVER', 
@database = N'my_PUBLICATION'
go

--===========================================================================================
--THAT DOES NOT GENERALLY GET RID OF THE JOBS FOR YOU
-- so you need to find them using these selects, and get rid of them manually yourself:

--select * from Distribution.dbo.MSpublications
--select * from Distribution.dbo.MSpublications
--===========================================================================================


select * from Distribution.[dbo].[MSlogreader_agents]
where publisher_db = N'my_PUBLICATION'

--found 1 job:
--PUBLISHER_SERVER-my_PUBLICATION-11

--script the job
--script the job delete script - and run that - keeping the job creation script just in case
exec msdb.dbo.sp_help_job @job_id=0x93C63D34E357704B818312B93FCA02FB
exec msdb.dbo.sp_delete_job @job_id=0x93C63D34E357704B818312B93FCA02FB



select * from Distribution.[dbo].[MSdistribution_agents]
where publisher_db = N'my_PUBLICATION'

--here found 2 jobs:

--PUBLISHER_SERVER-my_PUBLICATION-my_PUBLICATION--67
--PUBLISHER_SERVER-my_PUBLICATION-my_PUBLICATION--68


--here is the problem - it cannot find the jobs, the jobs are not even there anymore, one of those things
exec msdb.dbo.sp_delete_job @job_id=0x0F1564BAACD5464C988DE8957C25C411
exec msdb.dbo.sp_delete_job @job_id=0x6215C40F999CE248A30EE735E2C0E59D

--Msg 14262, Level 16, State 1, Procedure sp_verify_job_identifiers, Line 41 [Batch Start Line 52]
--The specified @job_id ('BA64150F-D5AC-4C46-988D-E8957C25C411') does not exist.


--Msg 14262, Level 16, State 1, Procedure sp_verify_job_identifiers, Line 41 [Batch Start Line 53]
--The specified @job_id ('0FC41562-9C99-48E2-A30E-E735E2C0E59D') does not exist.

exec msdb.dbo.sp_delete_job @job_name='PUBLISHER_SERVER-my_PUBLICATION-my_PUBLICATION'
PUBLISHER_SERVER-my_PUBLICATION-my_PUBLICATION--68

à ce stade, recréez la publication comme vous le feriez normalement

puis mettez l'instantané à exécuter

attendez qu'il ait fini de générer l'instantané

MAYBE YOU DONT NEED TO RUN THE SNAP - essayez without en l'exécutant en premier, la plupart du temps cela fonctionne, vous pouvez également ajouter seulement 1-2 small articles à la publication pour que le snap s'exécute rapidement

mais si vous exécutez l'instantané, vous devez attendre qu'il se termine avant de passer à l'étape suivante - drop the publication

enter image description here

après cela, vous générez les scripts pour drop that publication selon l'image ci-dessous: enter image description here

après cela, j'espère que lorsque vous exécutez nos scripts originaux ci-dessus , ou jetez un œil au moniteur de réplication, vous ne verrez pas la publication défectueuse, seulement les bonnes, dans mon cas juste une:

enter image description here

0