Como corrigir uma replicação desarrumada no MS SQL Server

11

Eu restaurei um banco de dados a partir de um backup. O banco de dados usa replicação para publicar em um servidor diferente. Supondo que a restauração do banco de dados interrompa a replicação, tentei excluí-la e recriá-la (temos um script para recriá-la do zero). Não sei exatamente o que fiz, mas agora ele está completamente bagunçado e não posso consertá-lo.

Primeiro, tento me livrar da assinatura (no servidor do editor):

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

Isso parece funcionar. SELECT * FROM syssubscriptionsnão mostra resultados. Procurando no servidor do assinante, SSMS> {SubscriberServer}> Replicação> Assinaturas Locais - a assinatura não existe.

Então, eu tento excluir a publicação. SSMS> {Servidor}> Replicação> Publicações Locais> {Nome da Publicação}> Excluir. Isso fornece a seguinte mensagem de erro:

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, então eu tento soltar os artigos:

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

e obtenha este erro:

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, então eu tento iniciar o Snapshot Agent e recebo esta exceção SQL interna:

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

Então, tentei um método alternativo de excluir o artigo DELETE FROM sysarticles,. Isso parece ter funcionado - agora me livrei dos artigos, mas continuo com o mesmo erro 'Não é possível descartar a publicação porque existe pelo menos uma assinatura para esta publicação' quando tento excluir a publicação.

Também reiniciei o SQL Server - não ajudou.

Não sei o que está acontecendo aqui e como faço para corrigir isso?

Aliás, é isso que acontece quando você fornece a um desenvolvedor de software que sabe o suficiente para ser perigoso as chaves do banco de dados. Felizmente, este não é um ambiente de produção ...

Cara alto
fonte

Respostas:

10

TLDR:

Parece que desabilitar e reativar a replicação provavelmente corrigiu o problema:

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

Eu acho que isso é o equivalente a desligá-lo e ligá-lo novamente ...

Versão mais longa:

Um colega de trabalho tentava consertar isso. Ele tentou algumas coisas, mas não foi muito longe. A única alteração que ele fez antes de desistir foi desativar a replicação.

Então tentei a sugestão de Cody . O comando sp_dropsubscription reclamou que não existem assinaturas. Então, eu tentei o comando sp_droppublication. Isso reclamou que a replicação não estava ativada no banco de dados. Então eu o habilitei e executei o comando novamente. Desta vez, reclamou que a publicação não existia. Atualizei o nó Publicações locais no SSMS e com certeza ele foi embora. Executei o script de configuração de replicação, gerei um novo instantâneo e agora tudo está funcionando corretamente. Alegria!

Não tenho 100% de certeza de que desabilitar e habilitar a replicação é o que realmente corrigiu o problema, mas definitivamente vale a pena tentar se a replicação for prejudicada.

Cara alto
fonte
Ótima leitura para iniciantes. É seguro dizer que você deve desativar a replicação antes de restaurar o banco de dados?
Keith Rivera
Certamente vou tentar isso da próxima vez - pelo que li, a replicação não deveria ter que ser completamente destruída e recriada (como eu pensava inicialmente). Desabilite a replicação, restaure o banco de dados, habilite a replicação, envie um novo instantâneo. Enquanto os artigos ainda forem válidos, deve ser bom ir. Vale a pena tentar de qualquer maneira ...
TallGuy
Novato de replicação total aqui, mas seguindo o TLDR; instruções levou ao desaparecimento de minhas publicações do SSMS. A consulta MSPublicationsno distributionbanco de dados revela que a publicação realmente se foi. Isso é esperado?
Pimbrouwers
5

Eu tive uma bagunça com a replicação e resolvi com isso

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

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

Isso e:

exec sp_cleanupdbreplication

São os salvadores ao limpar as replicações desarrumadas.

Guillermo Zooby
fonte
11
Acredito que sua postagem acabou de me salvar de redefinir meu ambiente de teste. Não tenho certeza de qual comando acima o fez, mas agora posso excluir índices sem o erro sobre eles serem publicados para replicação. Muito obrigado a você.
MHSQLDBA 13/04/19
2

Restaurar o banco de dados interromperá a replicação, o que é normal. Além disso, a maioria das outras mensagens de erro são apenas subseqüentes porque você não conseguiu remover todas as assinaturas (ou pelo menos o SQL pensa assim).

Você sabe que possui seu editor (o banco de dados de origem) e pelo menos um assinante (o banco de dados de destino) e que esses são dois servidores diferentes. Eu só quero mencionar que também há um distribuidor que está em um desses servidores ou em outro, e provavelmente em um banco de dados chamado distribuição. Às vezes, há algumas informações úteis e, às vezes, as coisas acontecem porque as informações entre os três não coincidem.

De qualquer forma, quando você verificou os assinantes, também verificou essa seção no servidor do editor para garantir que não havia mais nada listado? Se você encontrar algum, tente removê-lo manualmente:

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

Mas, supondo que eles realmente se foram, tente isso no banco de dados do editor:

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

Deixe-nos saber como vai. A replicação quando entra nesse estado me confunde e outros DBAs bons não têm nada a ver com ser um desenvolvedor :-)

Cody Konior
fonte
Obrigado pela sugestão. O comando sp_dropsubscription reclamou que não existem assinaturas. O comando sp_droppublication reclamou que a replicação não estava ativada - o que me levou ao que parece ser a solução.
precisa saber é o seguinte
Para mim, o comando sp_removedbreplication funcionava a maior parte do tempo sempre que eu tinha que remover a replicação à força.
SQLPRODDBA
0

A única maneira de me livrar dos artefatos de replicação fantasma é descartar as assinaturas, artigos, publicações. Se ainda houver assinaturas fantasmas, recrie a publicação, incluindo o assinante fantasma. Isso parece funcionar especialmente com versões mais antigas.

Edwina Montague-Martin
fonte
0

é o que normalmente faço quando tenho uma publicação que está bagunçada.

é um pouco feio, mas funcionou para mim em várias ocasiões em diferentes ambientes. o que causa isso? que às vezes é difícil descobrir isso, melhor, por vezes, é começar do zero, mas mesmo para isso você precisa de esclarecer alla residualspartir da publicação atual que está com defeito.

apenas para colocar em contexto:

É o que vejo no monitor de replicação:

insira a descrição da imagem aqui

e quando eu uso meu próprio monitor de replicação usando 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 

você pode ver duas linhas na última caixa abaixo - e uma delas não deve estar lá:

insira a descrição da imagem aqui

o mesmo quando eu uso este script:

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

insira a descrição da imagem aqui

Primeiro, faça o que é mostrado nas outras respostas acima, se isso funcionar , tudo bem, às vezes funciona, problema resolvido.

isso seria mais ou menos isso:

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

Agora, para se livrar completamente desta publicação, começaremos por conexão com o buscriber, e depois o editor e o distribuidor conforme o script abaixo:

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

neste ponto, recrie a publicação como faria normalmente

em seguida, coloque o instantâneo para executar

espere que ele termine de gerar o instantâneo

MAYBE YOU DONT NEED TO RUN THE SNAP- tente withoutexecutá-lo primeiro, na maioria das vezes ele funciona, você também pode adicionar apenas 1-2 smallartigos à publicação para que o snap seja executado rapidamente

mas se você executar o instantâneo, precisará esperar até que ele termine para poder ir para a próxima etapa - drop the publication

insira a descrição da imagem aqui

Depois disso, você gera os scripts drop that publicationconforme a imagem abaixo: insira a descrição da imagem aqui

depois disso, esperançosamente, quando você executar nossos scripts originais acima ou dar uma olhada no monitor de replicação, não verá a publicação com defeito, apenas as boas, no meu caso, apenas uma:

insira a descrição da imagem aqui

Marcello Miorelli
fonte
-1

Eu tive o mesmo problema na minha caixa de pré-produção, o comando

exec sp_cleanupdbreplication

parecem ter trabalhado na limpeza de entradas de assinatura falsas ...

CARLA
fonte