Configurar a resolução e detecção de conflitos do último gravador
A partir do SQL Server 2019 (15.x) CU 13, você pode configurar a replicação ponto a ponto para resolver conflitos automaticamente, permitindo que a inserção ou atualização mais recente ganhe o conflito. Se uma das gravações excluir a linha, o SQL Server permitirá a exclusão para superar o conflito. Esse método é chamado de Last Writer Wins.
Use procedimentos armazenados para configurar a última gravação vence. Não use o Assistente de Topologia Ponto a Ponto para adicionar ou remover nós quando você usar o último gravador.
Importantes considerações de configuração
Observação
Depois de atualizar para SQL Server 2019 (15.x) CU13 ou superior, quando você configura uma publicação com a resolução de conflitos última gravação vence, metadados adicionais são incluídos na publicação. Se posteriormente você desinstalar o SQL Server 2019 (15.x) CU13 ou fizer downgrade para uma versão inferior, esses metadados adicionais causarão problemas. Recomendamos descartar essas publicações antes de fazer o downgrade e recriá-las na versão inferior.
Ao configurar a replicação ponto a ponto com a descoberta e a resolução de conflitos automáticas com o método última gravação vence, inclua as seguintes configurações:
Crie a publicação com os seguintes parâmetros:
- Defina
@p2p_conflictdetection_policy = 'lastwriter'
para especificar a última gravação vence. Confira sp_addpublication (Transact-SQL). Esse parâmetro é introduzido no SQL Server 2019 (15.x) 13. O valor padrãooriginatorid
resolve o conflito com base na ID do originador e é o mesmo que a resolução de conflitos antes do SQL Server 2019 (15.x) CU 13. - Defina
@p2p_continue_onconflict = 'true'
para permitir que o agente de distribuição resolva o conflito.
- Defina
Ao adicionar o artigo (
sp_addarticle
), confirme o comportamento de tipo do comando de atualização (@upd_cmd
). As opções incluem:CALL
(Padrão)SCALL
Confira os detalhes em sp_addarticle (Transact-SQL).
Ao adicionar um artigo (
sp_addarticle
) a uma publicação com a política de detecção de conflito do último gravador, useCALL
ouSCALL
como tipo de comando para o parâmetro@upd_cmd
. O padrão éCALL
.Observação
O SQL Server dá suporte para
SCALL
ou@upd_cmd
. Com oSCALL
, quando uma transação atualiza um valor para o mesmo valor, ela não é considerada como uma alteração, e o formatoSCALL
não fornece o valor para colunas que não são atualizadas ou modificadas. Confira mais detalhes sobre o formato de chamada SCALL em Sintaxe de chamada para procedimentos armazenados.Você pode usar a publicação ponto a ponto com a detecção e resolução de conflitos do último gravador em um grupo de disponibilidade. Consulte:
Você pode ver o conflito e a resolução.
- No SQL Server Management Studio, clique com o botão direito do mouse na publicação e selecione Exibir Conflitos.
Ou
- Consulte
conflict_schemaname_tablename
no banco de dados de publicação. Por exemplo:conflict_dbo_tab1
. Confira conflict_<schema>_<table> (Transact-SQL).
Os conflitos de inserção e de atualização são resolvidos com base no último gravador, mas a exclusão sempre prevalece. Por exemplo, caso haja um conflito entre uma exclusão e uma atualização posterior, a exclusão ainda vence.
A detecção e a resolução de conflitos do último gravador são determinadas com base na coluna oculta
$sys_mw_cd_id
. O tipo de dados da coluna édatetime2
.
Comparação de detecção de conflitos
A seguinte tabela compara como os conflitos são detectados e resolvidos com a replicação ponto a ponto tradicional e quando a resolução de conflitos do último gravador é habilitada:
Tipo de conflito | Detalhes do conflito | Ponto a ponto | Último gravador |
---|---|---|---|
Inserção – inserção | Todas as linhas em cada tabela que participa da replicação ponto a ponto são identificadas exclusivamente usando valores de chave primários. Um conflito inserção-inserção ocorre quando uma linha com o mesmo valor de chave é inserida em mais de um nó. | Se a linha de entrada for a vencedora, atualizaremos a linha de destino. Em ambos os casos, registramos as informações. | Se a linha de entrada for a vencedora, atualizaremos a linha de destino. Em ambos os casos, registramos as informações. |
Atualização – atualização | Ocorre quando a mesma linha foi atualizada em mais de um nó. | Se a linha de entrada for a vencedora, modificaremos APENAS as colunas alteradas. | Se a linha de entrada for a vencedora, modificaremos todas as colunas no destino (se @upd_cmd estiver definido como default – CALL). |
Atualização – inserção | Ocorre quando uma linha é atualizada em um nó, mas a mesma linha é excluída e reinserida em outro nó. | Se a linha de entrada for a vencedora, modificaremos APENAS as colunas alteradas. | Isso ocorre quando uma linha é atualizada no peer1, e a mesma linha é excluída e inserida novamente no peer2. Quando a sincronização ocorre, a linha no peer1 é excluída (já que a exclusão sempre vence), e a mesma linha é inserida, enquanto a linha é atualizada em peer2 já que a atualização aconteceu depois. Isso resulta em não convergência. |
Inserção – atualização | Ocorre quando uma linha é excluída e reinserida em um nó, e a mesma linha é atualizada em outro nó. | Se a linha de entrada for a vencedora, atualizaremos todas as colunas. | Isso ocorre quando uma linha é excluída e reinserida no peer1, e a mesma linha é atualizada no peer2. Quando a sincronização ocorre, a linha é excluída no peer2 (já que a exclusão sempre vence) e depois inserida novamente. No peer1, a atualização é ignorada. |
Exclusão – Inserção Inserção – Exclusão |
Ocorre se uma linha foi excluída em um nó, mas a mesma linha foi excluída e, em seguida, reinserida em outro nó. | No momento, acreditamos que isso é um conflito D-U. Portanto, se a linha de entrada for a vencedora, excluiremos a linha do destino. | Isso ocorre quando uma linha é excluída no peer1, e a mesma linha é excluída e reinserida no peer2. Quando a sincronização ocorre, a linha no peer2 é excluída, enquanto a linha é inserida no peer1. Isso ocorre porque não armazenamos informações sobre a linha excluída, portanto, não sabemos se ela foi excluída ou não estava presente no par. Isso resulta em não convergência. |
Exclusão – Atualização | Ocorre quando uma linha é excluída em um nó, mas a mesma linha é atualizada em outro nó. | No momento, acreditamos que isso é um conflito D-U. Portanto, se a linha de entrada for a vencedora, excluiremos a linha do destino. | Este é um conflito D-U. Como a exclusão sempre vence, a exclusão de entrada será a vencedora, e excluiremos a linha do destino. |
Atualização – Exclusão | Ocorre se uma linha foi atualizada em um nó, mas a mesma linha foi excluída em outro. | No procedimento armazenado de atualização ponto a ponto, quando há um conflito U-D, imprimimos a mensagem a seguir e não o resolvemos. An update-delete conflict was detected and unresolved. The row could not be updated since the row does not exist. |
Este é um conflito U-D. Como a exclusão sempre vence, a atualização de entrada é ignorada. |
Exclusão – Exclusão | Ocorre quando uma linha foi excluída em mais de um nó. | No procedimento armazenado de exclusão ponto a ponto, quando há um conflito D-D, não processamos alterações e apenas o registramos. | Quando há um conflito D-D, não processamos alterações e apenas o registramos. |
Observação
Na implementação atual da política de detecção de conflitos do último gravador, a exclusão sempre vence quando há um conflito inserção – exclusão ou atualização – exclusão.
Exemplos
Criar publicação no primeiro par (Node1)
Neste exemplo, o script faz o seguinte:
- Publica um banco de dados chamado
MWPubDB
. - Dá o nome
PublMW
à publicação. - Configura a política de detecção e resolução de conflitos como última gravação vence:
, @p2p_continue_onconflict= 'true'
, @p2p_conflictdetection_policy = 'lastwriter'
USE [MWPubDB]
EXEC sp_replicationdboption @dbname = N'MWPubDB'
, @optname = N'publish'
, @value = N'true'
GO
-- Adding the transactional publication
USE [MWPubDB]
EXEC sp_addpublication @publication = N'PublMW'
, @description = N'Peer-to-Peer publication of database ''MWPubDB'' from Publisher ''Node1''.'
, @sync_method = N'native'
, @retention = 0
, @allow_push = N'true'
, @allow_pull = N'true'
, @allow_anonymous = N'false'
, @enabled_for_internet = N'false'
, @snapshot_in_defaultfolder = N'true'
, @compress_snapshot = N'false'
, @ftp_port = 21
, @allow_subscription_copy = N'false'
, @add_to_active_directory = N'false'
, @repl_freq = N'continuous'
, @status = N'active'
, @independent_agent = N'true'
, @immediate_sync = N'true'
, @allow_sync_tran = N'false'
, @allow_queued_tran = N'false'
, @allow_dts = N'false'
, @replicate_ddl = 1, @allow_initialize_from_backup = N'true'
, @enabled_for_p2p = N'true'
, @enabled_for_het_sub = N'false'
, @p2p_conflictdetection = N'true'
, @p2p_originator_id = 100
, @p2p_continue_onconflict= 'true'
, @p2p_conflictdetection_policy = 'lastwriter'
GO
USE [MWPubDB]
EXEC sp_addarticle @publication = N'PublMW'
, @article = N'tab1'
, @source_owner = N'dbo'
, @source_object = N'tab1'
, @type = N'logbased'
, @description = null
, @creation_script = null
, @pre_creation_cmd = N'drop'
, @schema_option = 0x0000000008035DDB
, @identityrangemanagementoption = N'manual'
, @destination_table = N'tab1'
, @destination_owner = N'dbo'
, @status = 16
, @vertical_partition = N'false'
, @ins_cmd = N'CALL sp_MSins_dbotab1'
, @del_cmd = N'CALL sp_MSdel_dbotab1'
, @upd_cmd = N'CALL sp_MSupd_dbotab1'
GO
Criar publicação no segundo par (Node2)
O script abaixo cria a publicação no segundo par (Node2).
USE [MWPubDB]
EXEC sp_replicationdboption @dbname = N'MWPubDB'
, @optname = N'publish'
, @value = N'true'
GO
-- Adding the transactional publication
USE [MWPubDB]
EXEC sp_addpublication @publication = N'PublMW'
, @description = N'Peer-to-Peer publication of database ''MWPubDB'' from Publisher ''Node2''.'
,@sync_method = N'native'
, @retention = 0, @allow_push = N'true'
, @allow_pull = N'true'
, @allow_anonymous = N'false'
, @enabled_for_internet = N'false'
, @snapshot_in_defaultfolder = N'true'
, @compress_snapshot = N'false'
, @ftp_port = 21, @allow_subscription_copy = N'false'
, @add_to_active_directory = N'false'
, @repl_freq = N'continuous'
, @status = N'active'
, @independent_agent = N'true'
, @immediate_sync = N'true'
, @allow_sync_tran = N'false'
, @allow_queued_tran = N'false'
, @allow_dts = N'false'
, @replicate_ddl = 1, @allow_initialize_from_backup = N'true'
, @enabled_for_p2p = N'true'
, @enabled_for_het_sub = N'false'
, @p2p_conflictdetection = N'true'
, @p2p_originator_id = 1
, @p2p_continue_onconflict= 'true'
, @p2p_conflictdetection_policy = 'lastwriter'
GO
USE [MWPubDB]
EXEC sp_addarticle @publication = N'PublMW'
, @article = N'tab1'
, @source_owner = N'dbo'
, @source_object = N'tab1'
, @type = N'logbased'
, @description = null
, @creation_script = null
, @pre_creation_cmd = N'drop'
, @schema_option = 0x0000000008035DDB
, @identityrangemanagementoption = N'manual'
, @destination_table = N'tab1'
, @destination_owner = N'dbo'
, @status = 16, @vertical_partition = N'false'
, @ins_cmd = N'CALL sp_MSins_dbotab1'
, @del_cmd = N'CALL sp_MSdel_dbotab1'
, @upd_cmd = N'CALL sp_MSupd_dbotab1'
GO
Criar assinatura de Node1 para Node2
USE [MWPubDB]
EXEC sp_addsubscription @publication = N'PublMW'
, @subscriber = N'Node2'
, @destination_db = N'MWPubDB'
, @subscription_type = N'Push'
, @sync_type = N'replication support only'
, @article = N'all'
, @update_mode = N'read only'
, @subscriber_type = 0
GO
EXEC sp_addpushsubscription_agent @publication = N'PublMW'
, @subscriber = N'Node2'
, @subscriber_db = N'MWPubDB'
, @job_login = null
, @job_password = null
, @subscriber_security_mode = 1
, @frequency_type = 64
, @frequency_interval = 1
, @frequency_relative_interval = 1
, @frequency_recurrence_factor = 0
, @frequency_subday = 4
, @frequency_subday_interval = 5
, @active_start_time_of_day = 0
, @active_end_time_of_day = 235959
, @active_start_date = 0
, @active_end_date = 0
, @dts_package_location = N'Distributor'
GO
Criar assinatura de Node2 para Node1
USE [MWPubDB]
EXEC sp_addsubscription @publication = N'PublMW'
, @subscriber = N'Node1'
, @destination_db = N'MWPubDB'
, @subscription_type = N'Push',
@sync_type = N'replication support only'
, @article = N'all'
, @update_mode = N'read only'
, @subscriber_type = 0
go
EXEC sp_addpushsubscription_agent @publication = N'PublMW'
, @subscriber = N'Node1'
, @subscriber_db = N'MWPubDB'
, @job_login = null
, @job_password = null
, @subscriber_security_mode = 1
, @frequency_type = 64
, @frequency_interval = 1
, @frequency_relative_interval = 1
, @frequency_recurrence_factor = 0
, @frequency_subday = 4
, @frequency_subday_interval = 5
, @active_start_time_of_day = 0
, @active_end_time_of_day = 235959
, @active_start_date = 0
, @active_end_date = 0
, @dts_package_location = N'Distributor'
GO
Confira também
- Ponto a ponto – Detecção de conflitos na replicação ponto a ponto
- Artigos transacionais – Especificar como as alterações são propagadas
- sp_addpublication (Transact-SQL)
- Configurar o banco de dados de publicação ponto a ponto para fazer parte do grupo de disponibilidade
- Configurar o banco de dados de publicação ponto a ponto para fazer parte dos grupos de disponibilidade