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 predeterminadooriginatorid
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.
- Establezca
Al agregar el artículo (
sp_addarticle
), confirme el comportamiento del tipo de comando para el comando update (@upd_cmd
). Entre las opciones se 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, useCALL
oSCALL
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
. ConSCALL
, cuando una transacción actualiza un valor al mismo valor, no se considera un cambio y el formatoSCALL
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
- Consulte
conflict_schemaname_tablename
en la base de datos de publicaciones. Por ejemplo:conflict_dbo_tab1
. Consulte conflict_<schema>_<table> (Transact-SQL).
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 esdatetime2
.
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
Contenido relacionado
- Detección de conflictos en la replicación punto a punto
- Artículos transaccionales: especificar cómo se propagan los cambios
- sp_addpublication (Transact-SQL)
- Configuración de un nodo del mismo nivel como parte de un grupo de disponibilidad
- Configuración de ambos nodos del mismo nivel en grupos de disponibilidad