Konfigurieren der Konflikterkennung und -lösung durch letzten Writer
Ab SQL Server 2019 (15.x) CU 13 können Sie die Peer-zu-Peer-Replikation so konfigurieren, dass Konflikte automatisch gelöst werden, indem die letzte Einfügung oder Aktualisierung den Konflikt gewinnt. Wenn ein Schreibvorgang die Zeile löscht, lässt SQL Server zu, dass der Löschvorgang den Konflikt gewinnt. Diese Methode wird als „last write wins“ (letzter Schreibvorgang gewinnt) bezeichnet.
Verwenden Sie gespeicherte Prozeduren, um den letzten Schreibvorgang zu konfigurieren. Verwenden Sie den Peer-to-Peer-Topologie-Assistenten nicht, um Knoten hinzuzufügen oder zu entfernen, wenn Sie den letzten Writer verwenden.
Wichtige Überlegungen zur Konfiguration
Hinweis
Wenn Sie nach dem Aktualisieren auf SQL Server 2019 (15.x) CU13 oder höher eine Veröffentlichung konfigurieren, bei der die Konfliktlösung auf den letzten Schreibvorgang festgelegt ist, werden zusätzliche Metadaten in die Veröffentlichung eingeschlossen. Wenn Sie SQL Server 2019 (15.x) CU13 später deinstallieren oder auf ein früheres Release downgraden, verursachen diese zusätzlichen Metadaten Probleme. Es wird empfohlen, solche Veröffentlichungen vor dem Downgrade zu trennen und sie dann in der früheren Version neu zu erstellen.
Wenn Sie die Peer-zu-Peer-Replikation mit automatischer Konflikterkennung und -lösung so konfigurieren, dass Konflikte durch den letzten Schreibvorgang gelöst werden, wenden Sie die folgenden Konfigurationen und Einstellungen an:
Erstellen Sie die Veröffentlichung mit den folgenden Parametern:
- Legen Sie
@p2p_conflictdetection_policy = 'lastwriter'
so fest, dass der letzte Schreibvorgang den Konflikt löst. Weitere Informationen finden Sie in sp_addpublication (Transact-SQL). Dieser Parameter wird in SQL Server 2019 (15.x) CU 13 eingeführt. Der Standardwertoriginatorid
löst Konflikte basierend auf der Absender-ID und entspricht der Konfliktlösung vor SQL Server 2019 (15.x) CU 13. - Legen Sie diese Einstellung
@p2p_continue_onconflict = 'true'
fest, damit der Verteilungs-Agent den Konflikt lösen kann.
- Legen Sie
Wenn Sie den Artikel (
sp_addarticle
) hinzufügen, bestätigen Sie das Verhalten des Befehlstyps für den Updatebefehl (@upd_cmd
). Beispiele für Optionen:CALL
(Standard)SCALL
Weitere Details finden Sie in sp_addarticle (Transact-SQL).
Wenn Sie einen Artikel (
sp_addarticle
) einer Veröffentlichung mit einer Richtlinie für die Konflikterkennung mithilfe des letzten Schreibvorgangs, USECALL
oderSCALL
als Befehlstyp für Parameter@upd_cmd
hinzufügen, istCALL
der Standard.Hinweis
SQL Server unterstützt
SCALL
für@upd_cmd
. Wenn eine Transaktion einen Wert auf denselben Wert aktualisiert, wird er mitSCALL
nicht als Änderung betrachtet, und das FormatSCALL
stellt den Wert nicht für Spalten bereit, die nicht aktualisiert oder geändert wurden. Ausführliche Informationen zum SCALL-Aufrufformat finden Sie unter Aufrufsyntax für gespeicherte Prozeduren.Sie können die Peer-zu-Peer-Veröffentlichung mit Konflikterkennung und -lösung durch den letzten Schreibvorgang in einer Verfügbarkeitsgruppe nutzen. Thema
Sie können den Konflikt und die Lösung einsehen.
- Klicken Sie in SQL Server Management Studio mit der rechten Maustaste auf die Publikation, und klicken Sie dann auf Konflikte anzeigen.
Oder
- Wählen
conflict_schemaname_tablename
Sie eine Veröffentlichungsdatenbank aus. Zum Beispielconflict_dbo_tab1
. Weitere Informationen finden Sie unter conflict_<schema>_<table> (Transact-SQL).
Einfüge- und Updatekonflikte werden auf der Grundlage des letzten Schreibvorgangs gelöst, doch Löschen ist immer die höchste Instanz. Wenn Sie zum Beispiel einen Löschen-Update-Konflikt haben und das Update später ausgeführt wurde, wird dennoch gelöscht.
Konflikterkennung und -lösung mithilfe des letzten Schreibvorgangs wird basierend auf einer ausgeblendeten Spalte
$sys_mw_cd_id
geregelt. Der Datentyp dieser Spalte istdatetime2
.
Konflikterkennungsvergleich
In der folgenden Tabelle wird verglichen, wie Konflikte mit herkömmlicher Peer-zu-Peer-Replikation erkannt und gelöst werden und wann die Konfliktlösung mithilfe des letzten Schreibvorgangs aktiviert ist:
Konflikttyp | Konfliktdetails | Peer-to-Peer | Letzter Schreibvorgang |
---|---|---|---|
Insert-insert | Alle Zeilen in einer Tabelle, die an der Peer-zu-Peer-Replikation beteiligt sind, werden mithilfe von Primärschlüsselwerten eindeutig identifiziert. Ein Konflikt vom Typ "insert-insert" tritt auf, wenn eine Zeile mit demselben Schlüsselwert an mehreren Knoten eingefügt wurde. | Wenn die eingehende Zeile gewinnt, aktualisieren Sie die Zielzeile. In beiden Fällen werden die Informationen aufgezeichnet. | Wenn die eingehende Zeile gewinnt, aktualisieren Sie die Zielzeile. In beiden Fällen werden die Informationen aufgezeichnet. |
Update-update | Tritt auf, wenn eine Zeile an mehreren Knoten aktualisiert wurde. | Wenn die eingehende Zeile gewinnt, ändern Sie NUR die geänderten Spalten. | Wenn die eingehende Zeile gewinnt, ändern Sie alle Spalten im Zielort (wenn @upd_cmd als default festgelegt ist – CALL). |
Update-insert | Dies tritt auf, wenn eine Zeile an einem Knoten aktualisiert wurde, diese Zeile jedoch gelöscht und dann an einem anderen Knoten wieder eingefügt wurde. | Wenn die eingehende Zeile gewinnt, ändern Sie NUR die geänderten Spalten. | Dies tritt auf, wenn eine Zeile auf Peer1 aktualisiert wird und dieselbe Zeile gelöscht und auf Peer2 erneut eingefügt wird. Wenn die Synchronisierung erfolgt, wird die Zeile auf Peer1 gelöscht, da Löschen immer gewinnt. Dann wird dieselbe Zeile wieder eingefügt. Die Zeile auf Peer2 hingegen wird aktualisiert, da die Aktualisierung zu einem späteren Zeitpunkt erfolgte. Dies führt zu Nichtübereinfluss. |
Insert-update | Dies tritt auf, wenn eine Zeile an einem Knoten gelöscht und dann wieder eingefügt wurde und dieselbe Zeile an einem anderen Knoten aktualisiert wurde. | Wenn die eingehende Zeile gewinnt, aktualisieren Sie alle Spalten. | Dies tritt auf, wenn eine Zeile auf Peer1 gelöscht und wieder eingefügt wird und dieselbe Zeile auf Peer2 aktualisiert wird. Wenn die Synchronisierung erfolgt, wird die Zeile auf Peer2 gelöscht, da Löschen immer gewinnt, und dann wieder eingefügt. Auf Peer1 wird die Aktualisierung übersprungen. |
Delete-Insert Insert-Delete |
Tritt auf, wenn eine Zeile an einem Knoten gelöscht wurde, diese Zeile aber gelöscht und dann an einem anderen Knoten erneut eingefügt wurde. | Dies wird derzeit als D-u-Konflikt betrachtet. Wenn die eingehende Zeile gewinnt, löschen Sie die Zeile aus dem Ziel. | Dies tritt auf, wenn eine Zeile auf Peer1 gelöscht und dieselbe Zeile auf Peer2 gelöscht und wieder eingefügt wird. Wenn die Synchronisierung erfolgt, wird die Zeile auf Peer2 gelöscht. Auf Peer1 hingegen wird die Zeile eingefügt. Dies liegt daran, dass wir keine Informationen über die gelöschte Zeile speichern und so nicht wissen, ob die Zeile gelöscht wurde oder auf dem Peer nicht vorhanden war. Dies führt zu Nichtübereinfluss. |
Delete-Update | Dies tritt auf, wenn eine Zeile an einem Knoten gelöscht wurde, dieselbe Zeile jedoch an einem anderen Knoten aktualisiert wurde. | Dies wird derzeit als D-u-Konflikt betrachtet. Wenn die eingehende Zeile gewinnt, löschen Sie die Zeile aus dem Ziel. | Dies ist ein D-u-Konflikt. Da Löschen immer gewinnt, gewinnt das eingehende Löschen, und Sie löschen die Zeile aus dem Ziel. |
Update-Delete | Tritt auf, wenn eine Zeile an einem Knoten aktualisiert wurde, diese Zeile aber an einem anderen Knoten gelöscht wurde. | Wenn in der gespeicherten Prozedur „Peer-to-Peer Update“ ein U-d-Konflikt vorliegt, geben Sie die folgende Meldung aus und lösen den Konflikt nicht. An update-delete conflict was detected and unresolved. The row could not be updated since the row does not exist. |
Dies ist ein U-d-Konflikt. Da das Löschen immer gewinnt, wird die eingehende Aktualisierung übersprungen. |
Delete-Delete | Tritt auf, wenn eine Zeile an mehreren Knoten gelöscht wurde. | Wenn in der gespeicherten Prozedur „Peer-to-Peer Delete“ ein D-d-Konflikt vorliegt, wenden Sie keine Änderungen an und zeichnen sie nur auf. | Wenn ein D-d-Konflikt vorliegt, verarbeiten Sie keine Änderungen und zeichnen sie nur auf. |
Hinweis
Aufgrund der aktuellen Implementierung der Konflikterkennungsrichtlinie mithilfe des letzten Schreibvorgangs gewinnt das Löschen immer dann, wenn ein Insert-delete-, Delete-insert- oder ein Update-delete-Konflikt vorliegt.
Beispiele
Erstellen einer Veröffentlichung auf dem ersten Peer (Node1)
Zum Beispiel das Skript:
- Veröffentlicht eine Datenbank mit dem Namen
MWPubDB
. - Benennt die Veröffentlichung
PublMW
. - Konfiguriert die Konflikterkennungs- und -lösungsrichtlinie, sodass der letzte Schreibvorgang gewinnt:
, @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
Erstellen einer Veröffentlichung auf dem zweiten Peer (Node2)
Das folgende Skript erstellt die Veröffentlichung auf dem zweiten Peer (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
Erstellen eines Abonnements von Node1 nach 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
Erstellen eines Abonnements von Node2 nach 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
Zugehöriger Inhalt
- Peer-zu-Peer – Konflikterkennung bei der Peer-zu-Peer-Replikation
- Transaktionsartikel – Angeben der Weitergabemethode für Änderungen
- sp_addpublication (Transact-SQL)
- Konfigurieren der Peer-zu-Peer-Veröffentlichungsdatenbank als Teil der Verfügbarkeitsgruppe
- Konfigurieren der Peer-zu-Peer-Veröffentlichungsdatenbank als Teil der Verfügbarkeitsgruppen