Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Начиная с SQL Server 2019 (15.x) CU13, можно настроить одноранговую репликацию для автоматического разрешения конфликтов, позволяя последней вставке или обновлению победить конфликт. Если запись удаляет строку, SQL Server позволяет удалить конфликт. Этот метод называется последней победой записи.
Используйте хранимые процедуры для настройки последних побед записи. Не используйте мастер одноранговой топологии для добавления или удаления узлов при использовании последнего средства записи.
Важные рекомендации по настройке
Замечание
После обновления до SQL Server 2019 (15.x) CU13 или более поздней версии при настройке публикации с разрешением конфликтов, установленной для последней записи, дополнительные метаданные включены в публикацию. При последующем удалении или понижении до выпуска, предшествующем sql Server 2019 (15.x) CU13, эта дополнительная метаданные приводит к проблемам. Перед понижением уровня следует удалить все такие публикации, а затем повторно создать их в более низкой версии.
При настройке одноранговой репликации с автоматическим обнаружением конфликтов и разрешением для разрешения в качестве последней победы записи включите следующие конфигурации и параметры:
Создайте публикацию со следующими параметрами.
Задайте для
@p2p_conflictdetection_policy = 'lastwriter'указания последних побед записи. См. sp_addpublication (Transact-SQL). Этот параметр представлен в SQL Server 2019 (15.x) CU13. Значениеoriginatoridпо умолчанию разрешает конфликт на основе идентификатора источника и совпадает с разрешением конфликтов до SQL Server 2019 (15.x) CU13.Задайте для
@p2p_continue_onconflict = 'true'разрешения конфликта агент распространителя.
При добавлении статьи (
sp_addarticle) подтвердите поведение типа команды для команды обновления (@upd_cmd). Возможные варианты:-
CALL(по умолчанию) SCALL
Дополнительные сведения см. в sp_addarticle.
-
При добавлении статьи (
sp_addarticle) в публикацию с политикойCALLобнаружения конфликтов последнего модуля записи используется илиSCALLв качестве типа команд для@upd_cmdпараметра поCALLумолчанию.Замечание
SQL Server поддерживает
SCALL@upd_cmdдля . ЕслиSCALLтранзакция обновляет значение до того же значения, он не считается изменением иSCALLформатом не предоставляет значение столбцов, которые не обновляются или не изменяются. Дополнительные сведения о формате вызова SCALL см. в разделе "Синтаксис вызова" для хранимых процедур.Вы можете использовать одноранговую публикацию с обнаружением и разрешением конфликтов последней записи в группе доступности. See:
Вы можете увидеть конфликт и его разрешение.
- В СРЕДЕ SQL Server Management Studio щелкните правой кнопкой мыши публикацию и выберите пункт "Просмотр конфликтов".
Or
- Запрос
conflict_schemaname_tablenameк базе данных публикации. Например:conflict_dbo_tab1. См. раздел conflict_<schema>_<table> (Transact-SQL).
Конфликты вставки и обновления разрешаются на основе последнего модуля записи, но всегда удаляются. Например, если у вас есть конфликт удаления и обновление было выполнено позже, удаление по-прежнему выигрывает.
Последнее обнаружение конфликтов записи и разрешение определяется на основе скрытого столбца
$sys_mw_cd_id. Тип данных этого столбца — datetime2.
Сравнение обнаружения конфликтов
В следующей таблице показано, как обнаружены и разрешаются конфликты с традиционной одноранговой репликацией и когда включено разрешение конфликтов последнего модуля записи:
| Тип конфликта | Сведения о конфликте | Одноранговый узел | Последний модуль записи |
|---|---|---|---|
| Insert-Insert | Все строки в каждой таблице, участвующие в одноранговой репликации, однозначно определяются с помощью значений первичного ключа. Конфликт вставки возникает, когда строка с одинаковым значением ключа была вставлена на нескольких узлах. | Если входящая строка является победителем, мы обновим целевую строку. В любом случае мы записываем информацию. | Если входящая строка является победителем, мы обновим целевую строку. В любом случае мы записываем информацию. |
| Update-Update | Происходит при обновлении одной строки на нескольких узлах. | Если входящая строка является победителем, мы изменим только измененные столбцы. | Если входящая строка является победителем, мы изменим все столбцы в назначении (если @upd_cmd задано значение default – CALL). |
| Update-Insert | Происходит, если строка была обновлена на одном узле, но одна и та же строка была удалена, а затем повторно включена на другой узел. | Если входящая строка является победителем, мы изменим только измененные столбцы. | Это происходит, когда строка обновляется peer1 и одна и та же строка удаляется и повторно включено peer2. Когда происходит синхронизация, строка peer1 удаляется, так как удаление всегда выигрывает, а затем вставляется та же строка, в то время как строка обновляется peer2 по мере обновления в дальнейшем. Это приводит к неконвергенции. |
| Вставка— обновление | Происходит, если строка была удалена, а затем повторно добавлена на один узел и одна и та же строка была обновлена на другом узле. | Если входящая строка является победителем, мы обновим все столбцы. | Это происходит при удалении и повторном включении peer1 строки и обновлении peer2той же строки. Когда происходит синхронизация, строка удаляется peer2 как удаление всегда выигрывает, а затем снова вставляется. В противном случае peer1обновление пропускается. |
| Delete-Insert Insert-Delete |
Происходит, если строка была удалена на одном узле, но одна и та же строка была удалена, а затем повторно добавлена на другой узел. | В настоящее время мы считаем, что это конфликт D-U, и если входящие строки являются победителем, то мы удаляем строку из назначения. | Это происходит, когда строка удаляется peer1 и одна и та же строка удаляется + повторно включено peer2. При синхронизации строка peer2 удаляется, а строка вставляется в peer1нее. Это происходит потому, что мы не храним сведения об удаленной строке, поэтому мы не знаем, была ли строка удалена или отсутствует в одноранговом узле. Это приводит к неконвергенции. |
| Delete-Update | Происходит, если строка была удалена на одном узле, но одна и та же строка была обновлена на другом узле. | В настоящее время мы считаем, что это конфликт D-U, и если входящая строка является победителем, то мы удаляем строку из назначения. | Это конфликт D-U. По мере того как удаление всегда выигрывает, входящее удаление является победителем, и мы удаляем строку из назначения. |
| Update-Delete | Происходит, если строка была обновлена на одном узле, но одна и та же строка была удалена на другом узле. | В хранимой процедуре однорангового обновления, если существует конфликт U-D, мы распечатаем следующее сообщение и не устраним его.An update-delete conflict was detected and unresolved. The row could not be updated since the row does not exist. |
Это конфликт U-D. По мере того как удаление всегда выигрывает, входящие обновления пропускаются. |
| Delete-Delete | Происходит при удалении строки на нескольких узлах. | В хранимой процедуре удаления одноранговых узлов, если существует конфликт D-D, мы не обрабатываем никаких изменений, просто запишите его. | Если есть конфликт D-D, то мы не обрабатываем никаких изменений, просто запишите его. |
Замечание
В текущей реализации политики обнаружения конфликтов записи удаление всегда выигрывает при наличии конфликта insert-delete, delete-insert или update-delete.
Примеры
Создание публикации на первом одноранговом узле (Node1)
В этом примере скрипт:
- Публикует вызываемую
MWPubDBбазу данных. - Именует публикацию
PublMW. - Настраивает политику обнаружения и разрешения конфликтов в качестве последней победы записи:
, @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
Создание публикации во втором одноранговом узле (Node2)
Следующий скрипт создает публикацию во втором одноранговом узле (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
Создание подписки из Node1 в 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
Создание подписки из Node2 в 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