Udostępnij przez


Konfigurowanie wykrywania konfliktów ostatniego piszącego i ich rozwiązywania &

Począwszy od programu SQL Server 2019 (15.x) CU13, można skonfigurować replikację równorzędną w celu automatycznego rozwiązywania konfliktów, umożliwiając najnowsze wstawianie lub aktualizację w celu wygrania konfliktu. Jeśli dowolny zapis usunie wiersz, program SQL Server umożliwia usunięcie w celu wygrania konfliktu. Ta metoda jest znana jako ostatnia wygrana zapisu.

Użyj procedur składowanych, aby skonfigurować ostatnie zwycięstwa zapisu. Nie używaj Kreatora topologii równorzędnej do dodawania lub usuwania węzłów podczas korzystania z ostatniego składnika zapisywania.

Ważne zagadnienia dotyczące konfiguracji

Uwaga / Notatka

Po aktualizacji do programu SQL Server 2019 (15.x) CU13 lub nowszej wersji podczas konfigurowania publikacji z rozwiązaniem konfliktów ustawionym na ostatnie zwycięstwo zapisu dodatkowe metadane zostaną uwzględnione w publikacji. Jeśli później odinstalujesz/obniżysz wersję do wersji starszej niż AKTUALIZACJA CU13 programu SQL Server 2019 (15.x), te dodatkowe metadane powodują problemy. Przed obniżeniem poziomu należy usunąć wszystkie takie publikacje, a następnie utworzyć je ponownie w niższej wersji.

Podczas konfigurowania replikacji równorzędnej za pomocą automatycznego odnajdywania konfliktów i rozwiązywania problemów w celu rozwiązania ich jako ostatnich zwycięstw zapisu uwzględnij następujące konfiguracje i ustawienia:

  • Utwórz publikację przy użyciu następujących parametrów:

    • Ustaw @p2p_conflictdetection_policy = 'lastwriter' wartość , aby określić ostatnią wygraną zapisu. Zobacz sp_addpublication (Transact-SQL). Ten parametr został wprowadzony w programie SQL Server 2019 (15.x) CU13. Wartość originatorid domyślna rozwiązuje konflikt na podstawie identyfikatora inicjatora i jest taka sama jak rozwiązywanie konfliktów przed programem SQL Server 2019 (15.x) CU13.

    • Ustaw @p2p_continue_onconflict = 'true' wartość , aby umożliwić agentowi dystrybucji rozwiązanie konfliktu.

  • Po dodaniu artykułu (sp_addarticle) potwierdź zachowanie typu polecenia dla polecenia aktualizacji (@upd_cmd). Dostępne są następujące opcje:

    • CALL (Ustawienie domyślne)
    • SCALL

    Zobacz szczegóły w sp_addarticle.

  • Jeśli dodasz artykuł (sp_addarticle) w publikacji z zasadami wykrywania konfliktów ostatniego składnika zapisywania, użyj CALL polecenia lub SCALL jako typ polecenia dla @upd_cmd parametru, CALL jest domyślny.

    Uwaga / Notatka

    Program SQL Server obsługuje program SCALL dla programu @upd_cmd. W SCALLprzypadku , gdy transakcja aktualizuje wartość do tej samej wartości, nie jest traktowana jako zmiana, a SCALL format nie dostarcza wartości kolumn, które nie są aktualizowane ani modyfikowane. Aby uzyskać więcej informacji na temat formatu wywołania SCALL, zobacz Wywoływanie składni procedur składowanych.

  • Publikacji równorzędnej można używać z wykrywaniem konfliktów ostatniego składnika zapisywania i rozwiązywaniem ich w grupie dostępności. Zobacz:

  • Możesz zobaczyć konflikt i jego rozwiązanie.

    • W programie SQL Server Management Studio kliknij publikację prawym przyciskiem myszy i wybierz polecenie Wyświetl konflikty.

    lub

  • Konflikty wstawiania i aktualizacji są rozwiązywane na podstawie ostatniego składnika zapisywania, ale usuwanie zawsze zwycięża. Jeśli na przykład wystąpił konflikt usuwania aktualizacji i aktualizacja została wykonana w późniejszym czasie, usunięcie nadal wygrywa.

  • Wykrywanie i rozwiązywanie konfliktów ostatniego składnika zapisywania jest określane na podstawie ukrytej kolumny $sys_mw_cd_id. Typ danych tej kolumny to data/godzina2.

Porównanie wykrywania konfliktów

W poniższej tabeli porównano, w jaki sposób konflikty są wykrywane i rozwiązywane przy użyciu tradycyjnej replikacji równorzędnej, a po włączeniu ostatniego rozwiązywania konfliktów składnika zapisywania:

Typ konfliktu Szczegóły konfliktu Peer-to-peer Ostatni zapis
Insert-Insert Wszystkie wiersze w każdej tabeli uczestniczące w replikacji równorzędnej są jednoznacznie identyfikowane przy użyciu wartości klucza podstawowego. Konflikt wstawiania występuje, gdy wiersz o tej samej wartości klucza został wstawiony w więcej niż jednym węźle. Jeśli wiersz przychodzący jest zwycięzcą, zaktualizujemy wiersz docelowy. W obu przypadkach rejestrujemy informacje. Jeśli wiersz przychodzący jest zwycięzcą, zaktualizujemy wiersz docelowy. W obu przypadkach rejestrujemy informacje.
Update-Update Występuje, gdy ten sam wiersz został zaktualizowany w więcej niż jednym węźle. Jeśli wiersz przychodzący jest zwycięzcą, zmodyfikujemy tylko zmienione kolumny. Jeśli wiersz przychodzący jest zwycięzcą, zmodyfikujemy wszystkie kolumny w miejscu docelowym (jeśli @upd_cmd ustawiono default wartość – CALL).
Update-Insert Występuje, jeśli wiersz został zaktualizowany w jednym węźle, ale ten sam wiersz został usunięty, a następnie ponownie zainstalowany w innym węźle. Jeśli wiersz przychodzący jest zwycięzcą, zmodyfikujemy tylko zmienione kolumny. Dzieje się tak, gdy wiersz jest aktualizowany peer1 , a ten sam wiersz jest usuwany i ponownie wyświetlany w pliku peer2. Po zakończeniu synchronizacji wiersz jest peer1 usuwany jako usunięcie zawsze wygrywa, a następnie ten sam wiersz jest wstawiany, podczas gdy wiersz jest aktualizowany peer2 w miarę późniejszego aktualizowania. Prowadzi to do niekonwergencencji.
Wstaw — aktualizacja Występuje, jeśli wiersz został usunięty, a następnie ponownie zainstalowany w jednym węźle, a ten sam wiersz został zaktualizowany w innym węźle. Jeśli wiersz przychodzący jest zwycięzcą, zaktualizujemy wszystkie kolumny. Dzieje się tak, gdy wiersz jest usuwany i ponownie wyświetlany, a ten sam wiersz jest aktualizowany peer1 w dniu peer2. Po zakończeniu synchronizacji wiersz jest usuwany peer2 jako usunięcie zawsze wygrywa, a następnie jest on wstawiany ponownie. W systemie peer1aktualizacja jest pomijana.
Delete-Insert

Insert-Delete
Występuje, jeśli wiersz został usunięty w jednym węźle, ale ten sam wiersz został usunięty, a następnie ponownie wyświetlony w innym węźle. Obecnie uważamy to za konflikt D-U, a jeśli przychodzący wiersz jest zwycięzcą, usuwamy wiersz z miejsca docelowego. Dzieje się tak, gdy wiersz jest usuwany, peer1 a ten sam wiersz jest usuwany i ponownie włączony .peer2 Po zakończeniu synchronizacji wiersz jest peer2 usuwany, podczas gdy wiersz jest wstawiany w pliku peer1. Dzieje się tak, ponieważ nie przechowujemy informacji o usuniętym wierszu, więc nie wiemy, czy wiersz został usunięty, czy nie był obecny w obiekcie równorzędnym. Prowadzi to do niekonwergencencji.
Delete-Update Występuje, jeśli wiersz został usunięty w jednym węźle, ale ten sam wiersz został zaktualizowany w innym węźle. Obecnie uważamy, że jest to konflikt D-U, a jeśli przychodzący wiersz jest zwycięzcą, usuwamy wiersz z miejsca docelowego. Jest to konflikt D-U. Usunięcie zawsze wygrywa, usunięcie przychodzące jest zwycięzcą i usuwamy wiersz z miejsca docelowego.
Update-Delete Występuje, jeśli wiersz został zaktualizowany w jednym węźle, ale ten sam wiersz został usunięty w innym węźle. W procedurze składowanej aktualizacji równorzędnej komunikacji równorzędnej, jeśli występuje konflikt U-D, wyświetlimy następujący komunikat i nie rozwiążemy problemu.

An update-delete conflict was detected and unresolved. The row could not be updated since the row does not exist.
Jest to konflikt U-D. Jak usuwanie zawsze wygrywa, aktualizacja przychodząca jest pomijana.
Delete-Delete Występuje, gdy wiersz został usunięty w więcej niż jednym węźle. W procedurze składowanej peer-to-peer Usuń, jeśli występuje konflikt D-D, nie przetwarzamy żadnych zmian, po prostu je rejestrujemy. Jeśli występuje konflikt D-D, to nie przetwarzamy żadnych zmian, po prostu je rejestrujemy.

Uwaga / Notatka

W bieżącej implementacji zasad wykrywania konfliktów ostatniego modułu zapisywania usunięcie zawsze jest wygrywane, gdy występuje konflikt operacji insert-delete, delete-insert lub update-delete.

Przykłady

Tworzenie publikacji w pierwszej komunikacji równorzędnej (Node1)

W tym przykładzie skrypt:

  • Publikuje bazę danych o nazwie MWPubDB.
  • Nadaj publikacji PublMWnazwę .
  • Konfiguruje zasady wykrywania konfliktów i rozwiązywania problemów podczas ostatniego zapisu wygrywa: , @p2p_continue_onconflict= 'true', @p2p_conflictdetection_policy = 'lastwriter'
USE [MWPubDB];

EXECUTE sp_replicationdboption
    @dbname = N'MWPubDB',
    @optname = N'publish',
    @value = N'true';
GO

-- Adding the transactional publication
USE [MWPubDB];

EXECUTE 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];

EXECUTE 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

Tworzenie publikacji na drugim elementach równorzędnych (Node2)

Poniższy skrypt tworzy publikację w drugim elementu równorzędnym (Node 2).

USE [MWPubDB];

EXECUTE sp_replicationdboption
    @dbname = N'MWPubDB',
    @optname = N'publish',
    @value = N'true';
GO

-- Adding the transactional publication
USE [MWPubDB];

EXECUTE 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];

EXECUTE 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

Tworzenie subskrypcji z węzła Node1 do węzła Node2

USE [MWPubDB];

EXECUTE 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

EXECUTE 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

Tworzenie subskrypcji z węzła Node2 do węzła Node1

USE [MWPubDB];

EXECUTE 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

EXECUTE 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