Как исправить испорченную репликацию на MS SQL Server


11

Я восстановил базу данных из резервной копии. База данных использует репликацию для публикации на другом сервере. Предполагая, что восстановление базы данных нарушит репликацию, я попытался удалить репликацию и заново создать ее (у нас есть сценарий для повторного создания с нуля). Я не совсем уверен, что именно я сделал, но сейчас он в совершенно запутанном состоянии, и я не могу это исправить.

Сначала я пытаюсь избавиться от подписки (на сервере издателя):

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

Это похоже на работу. SELECT * FROM syssubscriptionsне показывает результатов. Глядя на сервер подписчика, SSMS> {SubscriberServer}> Репликация> Локальные подписки - подписки там нет.

Тогда я пытаюсь удалить публикацию. SSMS> {Сервер}> Репликация> Локальные публикации> {PublicationName}> Удалить. Это дает следующее сообщение об ошибке:

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

Итак, я пытаюсь отбросить статьи:

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

и получите эту ошибку:

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.

Итак, я пытаюсь запустить агент моментальных снимков и получаю следующее внутреннее исключение SQL:

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

Поэтому я попробовал альтернативный метод удаления статьи DELETE FROM sysarticles. Кажется, это сработало - теперь я избавился от статей, но все равно получаю ту же ошибку «Невозможно удалить публикацию, потому что существует хотя бы одна подписка на эту публикацию» при попытке удалить публикацию.

Я также перезапустил SQL Server - не помогло.

Я не знаю, что здесь происходит и как мне это исправить?

Кстати, это то, что происходит, когда вы даете разработчику программного обеспечения, который знает достаточно, чтобы быть опасным, ключи к базе данных. К счастью, это не производственная среда ...

Ответы:


10

TLDR:

Похоже, что отключение и повторное включение репликации, вероятно, решило проблему:

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

Я полагаю, это эквивалентно выключению и повторному включению ...

Более длинная версия:

Товарищ по работе попытался это исправить. Он попробовал несколько вещей, но не очень далеко. Единственное изменение, которое он сделал перед отказом, - отключить репликацию.

Затем я попробовал предложение Коди . Команда sp_dropsubscription пожаловалась, что подписок не существует. Поэтому я попробовал команду sp_droppublication. Это жаловалось, что репликация не была включена в базе данных. Поэтому я включил его и снова запустил команду. На этот раз он пожаловался, что публикации не существует. Я обновил узел «Локальные публикации» в SSMS и убедился, что он исчез. Я запустил сценарий настройки репликации, сгенерировал новый снимок, и теперь все работает правильно. Радость!

Я не уверен на 100%, что отключение и включение репликации - это то, что действительно решило проблему, но определенно стоит попробовать, если репликация испортилась.


Отличное чтиво для новичков. Можно ли с уверенностью сказать, что вам следует отключить репликацию перед восстановлением базы данных?
Кит Ривера

Я, конечно, собираюсь попробовать это в следующий раз - из того, что я прочитал, репликация не должна быть полностью удалена и воссоздана (как я первоначально думал, что это будет). Отключите репликацию, восстановите базу данных, включите репликацию, отправьте новый снимок. Пока статьи все еще в силе, это должно быть хорошо. Стоит попробовать в любом случае ...
TallGuy

Полная репликация новичка здесь, но после TLDR; Инструкция привела к исчезновению моих публикаций из SSMS. Запросы MSPublicationsв distributionбазе данных показывают, что публикация действительно исчезла. Это ожидается?
pimbrouwers

5

У меня был беспорядок с репликацией и решил это с этим

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

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

Это и:

exec sp_cleanupdbreplication

Спасители при очистке перепутали репликации.


1
Я считаю, что ваше сообщение только что спасло меня от переустановки среды тестирования. Не уверен, какая команда выше сделала это, но теперь я могу удалить индексы без публикации ошибок для их репликации. Большое спасибо Вам.
MHSQLDBA

2

Восстановление базы данных нарушит репликацию, так что это нормально. Кроме того, большинство других сообщений об ошибках просто следуют, потому что вы не смогли удалить все подписки (или, по крайней мере, так считает SQL).

Вы знаете, что у вас есть издатель (исходная база данных) и хотя бы один подписчик (целевая база данных), и что это два разных сервера. Я просто хочу упомянуть, что есть также дистрибьютор, который находится на одном из этих серверов или на другом, и, вероятно, в базе данных, называемой распределением. Иногда там есть какая-то полезная информация, а иногда вещи падают, потому что информация между этими тремя не совпадает.

В любом случае, когда вы проверяли подписчиков, вы также проверяли этот раздел на сервере издателя, чтобы убедиться, что больше ничего не указано в списке? Если вы найдете что-нибудь, попробуйте удалить его вручную:

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

Но если предположить, что они действительно исчезли, попробуйте это в базе данных издателя:

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

Дайте нам знать, как оно идет. Репликация, когда она попадает в это состояние, смущает меня и других хороших администраторов баз данных, не имеющих никакого отношения к тому, чтобы быть разработчиком вообще :-)


Спасибо за предложение. Команда sp_dropsubscription пожаловалась, что подписок не существует. Команда sp_droppublication жаловалась, что репликация не была включена - что привело меня к тому, что кажется решением.
TallGuy

Для меня команда sp_removedbreplication работала большую часть времени, когда мне приходилось принудительно удалять репликацию.
SQLPRODDBA

0

Единственный способ избавиться от артефактов фантомной репликации - это удалить подписки, статьи, публикации. Если подписки по-прежнему существуют, то заново создайте публикацию, включая подписчика-фантомов. Это, кажется, работает с более старыми версиями особенно.


0

это то, что я обычно делаю, когда у меня испорчена публикация.

это немного некрасиво, но это работало для меня много раз в разных средах. что вызывает это? что иногда трудно понять это, лучше иногда начинать с нуля, но даже для этого вам нужно очистить от текущей публикации , что неисправен.allresiduals

просто чтобы поместить это в контекст:

Вот что я вижу из монитора репликации:

введите описание изображения здесь

и когда я использую свой собственный монитор репликации с использованием 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 

Вы можете видеть 2 строки в последнем окне ниже - и одна из них не должна быть там:

введите описание изображения здесь

то же самое, когда я использую этот скрипт:

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

введите описание изображения здесь

Сначала вы делаете то, что показано в других ответах выше, если это работает , это хорошо, иногда это работает, проблема решена.

это было бы более менее это:

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

Теперь, чтобы полностью избавиться от этой публикации, мы начнем с подключения к buscriber, а затем к издателю, а затем к распространителю, как показано ниже:

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

на этом этапе заново создайте публикацию, как вы это обычно делаете

затем поместите снимок для запуска

дождитесь завершения создания снимка

MAYBE YOU DONT NEED TO RUN THE SNAP- попробуйте withoutзапустить его сначала, большую часть времени он работает, также вы можете добавить 1-2 smallпубликации в публикацию, чтобы оснастка работала быстро

но если вы запускаете моментальный снимок, вам нужно подождать, пока он не закончится, прежде чем вы сможете перейти к следующему шагу - drop the publication

введите описание изображения здесь

после этого вы генерируете сценарии drop that publicationсогласно рисунку ниже: введите описание изображения здесь

надеюсь, что после этого, когда вы запустите наши оригинальные сценарии или посмотрите на монитор репликации, вы не увидите ошибочную публикацию, только хорошие, в моем случае только один:

введите описание изображения здесь


-1

У меня была такая же проблема на моей предсерийной коробке, команда

exec sp_cleanupdbreplication

похоже, работали над очисткой фиктивных подписок ...

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.