Configuración de la detección y resolución de conflictos del último objeto de escritura

A partir de SQL Server 2019 (15.x) CU13, puede configurar la replicación punto a punto para resolver automáticamente los conflictos permitiendo la inserción o la actualización más recientes a fin de ganar el conflicto. Si alguna de las escrituras elimina la fila, SQL Server permite que la eliminación corrija el conflicto. Este método se conoce como "últimos casos de escritura correcta".

Siga procedimientos almacenados para configurar los últimos casos de escritura correcta. No use el Asistente para topología punto a punto para agregar o quitar nodos cuando use el último escritor.

Consideraciones importantes sobre la configuración

Nota:

Después de actualizar a SQL Server 2019 (15.x) CU13 o posterior, al configurar una publicación con la resolución de conflictos establecida en los últimos casos de escritura correcta, se incluyen más metadatos en la publicación. Si posteriormente desinstala SQL Server 2019 (15.x) CU13 o cambia a una versión anterior, estos metadatos adicionales provocarán problemas. Se recomienda quitar estas publicaciones antes de degradarlas y, después, volver a crearlas en la versión inferior.

Al configurar la replicación punto a punto con la detección y la resolución automáticas de conflictos que se resuelven como últimos casos de escritura correcta, incluya las configuraciones y los valores siguientes:

  • Cree la publicación con los parámetros siguientes:

    • Establezca @p2p_conflictdetection_policy = 'lastwriter' para especificar los últimos casos de escritura correcta. Consulte sp_addpublication (Transact-SQL). Este parámetro se presenta en SQL Server 2019 (15.x) CU 13. El valor predeterminado originatorid resuelve el conflicto en función del identificador del originador y es igual que la resolución de conflictos anterior a SQL Server 2019 (15.x) CU13.
    • Establezca @p2p_continue_onconflict = 'true' para permitir que el agente de distribución resuelva el conflicto.
  • Al agregar el artículo (sp_addarticle), confirme el comportamiento del tipo de comando para el comando update (@upd_cmd). Las opciones incluyen:

    • CALL (Valor predeterminado)
    • SCALL

    Consulte los detalles en sp_addarticle (Transact-SQL).

  • Cuando se agrega un artículo (sp_addarticle) en una publicación con una directiva de detección de conflictos de último escritor, use CALL o SCALL como tipo de comando para el parámetro @upd_cmd, CALL es el valor predeterminado.

    Nota:

    SQL Server es compatible con SCALL para @upd_cmd. Con SCALL, cuando una transacción actualiza un valor al mismo valor, no se considera un cambio y el formato SCALL no proporciona el valor para las columnas que no se actualizan ni modifican. Revise lo siguiente para obtener más información sobre el formato de llamada SCALL: Sintaxis de llamada para procedimientos almacenados.

  • Puede usar la publicación punto a punto con la detección y resolución de últimos conflictos de escritura en un grupo de disponibilidad. Vea:

  • Puede ver el conflicto y su resolución.

    • En SQL Server Management Studio, haga clic con el botón derecho en el modelo y seleccione Ver conflictos.

    Or

  • Los conflictos de inserción y actualización se resuelven en función del último sistema de escritura, pero la eliminación siempre prevalece. Por ejemplo, si tiene un conflicto de eliminación y actualización y la actualización se ha realizado más tarde, la eliminación sigue teniendo prioridad.

  • La detección y resolución de conflictos del último escritor se determina en función de una columna oculta $sys_mw_cd_id. El tipo de datos de esta columna es datetime2.

Comparación de detección de conflictos

En la tabla siguiente se compara cómo se detectan y resuelven los conflictos con la replicación punto a punto tradicional y cuándo está habilitada la última resolución de conflictos de escritura:

Tipo de conflicto Detalles del conflicto Punto a punto Último escritor
Inserción-inserción Todas las filas de cada tabla que participa en una replicación punto a punto se identifican de forma exclusiva mediante valores de clave principal. Se produce un conflicto de inserción-inserción al insertar una fila con el mismo valor de clave en más de un nodo. Si la fila entrante es la que tiene prioridad, se actualiza la fila de destino. En cualquier caso, se registra la información. Si la fila entrante es la que tiene prioridad, se actualiza la fila de destino. En cualquier caso, se registra la información.
Actualización-actualización Se produce cuando se actualiza la misma fila en más de un nodo. Si la fila entrante es la que tiene prioridad, solo se modifican las columnas que han cambiado. Si la fila entrante es la que tiene prioridad, se modifican todas las columnas del destino (si @upd_cmd se establece en default – CALL).
Actualización-inserción Se produce cuando se actualiza una fila en un nodo, pero la misma fila se ha eliminado y luego se ha vuelto a insertar en otro nodo. Si la fila entrante es la que tiene prioridad, solo se modifican las columnas que han cambiado. Esto ocurre cuando se actualiza una fila en peer1 y se elimina y se vuelve a insertar la misma fila en peer2. Cuando se produce la sincronización, la fila de peer1 se elimina, ya que la eliminación siempre tiene prioridad y, después, se inserta la misma fila, mientras que la fila se actualiza en peer2, ya que la actualización se produjo en un momento posterior. Esto dará lugar a la no convergencia.
Inserción-actualización Se produce cuando se elimina una fila en un nodo y la misma fila se ha actualizado en otro nodo. Si la fila entrante tiene prioridad, se actualizan todas las columnas. Esto ocurre cuando se elimina una fila y luego se vuelve a insertar en peer1 y se actualiza la misma fila en peer2. Cuando se produce la sincronización, la fila se elimina en peer2, ya que la eliminación siempre tiene prioridad y, después, se vuelve a insertar. En peer1, se omite la actualización.
Eliminación-inserción

Inserción-eliminación
Se produce cuando se elimina una fila en un nodo, pero la misma fila se ha eliminado y, a continuación, se ha vuelto a insertar en otro nodo. Actualmente, se trata de un conflicto de eliminación-actualización y, si la fila entrante tiene prioridad, se elimina la fila del destino. Esto ocurre cuando se elimina una fila en peer1 y se elimina y se vuelve a insertar la misma fila en peer2. Cuando se produce la sincronización, se elimina la fila de peer2, mientras que la fila se inserta en peer1. Esto se produce porque no se almacena información sobre la fila eliminada, por lo que no se sabe si la fila se eliminó o no estaba presente en el mismo nivel. Esto dará lugar a la no convergencia.
Eliminación-actualización Se produce cuando se elimina una fila en un nodo, pero la misma fila se ha actualizado en otro nodo. Actualmente, se trata de un conflicto de eliminación-actualización y, si la fila entrante tiene prioridad, se elimina la fila del destino. Se trata de un conflicto de eliminación-actualización. Como la eliminación siempre tiene prioridad, la eliminación entrante tendrá prioridad y se eliminará la fila del destino.
Actualización-eliminación Se produce cuando se actualiza una fila en un nodo, pero la misma fila se ha eliminado en otro nodo. En el procedimiento almacenado de actualización punto a punto, si hay un conflicto de actualización-eliminación, se muestra el mensaje siguiente y no se resuelve.

An update-delete conflict was detected and unresolved. The row could not be updated since the row does not exist.
Se trata de un conflicto de actualización-eliminación. Como la eliminación siempre tiene prioridad, se omite la actualización entrante.
Eliminación-eliminación Se produce cuando se elimina una fila en más de un nodo. En el procedimiento almacenado de eliminación punto a punto, si hay un conflicto de eliminación-eliminación, no se procesa ningún cambio, simplemente se registra. Si hay un conflicto de eliminación-eliminación, no se procesa ningún cambio, simplemente se registra.

Nota:

En la implementación actual de la última directiva de detección de conflictos de escritor, la eliminación siempre tiene prioridad cuando hay un conflicto de inserción-eliminación, de eliminación-inserción o de actualización-eliminación.

Ejemplos

Creación de una publicación en el primer nodo del mismo nivel (Node1)

En este ejemplo, el script:

  • Publica una base de datos llamada MWPubDB.
  • Denomina a la publicación PublMW.
  • Configura la directiva de detección y resolución de conflictos como últimos casos de escritura correcta:
    , @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

Creación de una publicación en el segundo nodo del mismo nivel (Node2)

El script siguiente crea la publicación en el segundo nodo del mismo nivel (Nodo 2).

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

Creación de una suscripción de Node1 a 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

Creación de una suscripción de Node1 a Node2

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

Consulte también