Как правильно реализовать MERGE для таблиц? Неверный результат CDC
Один раз в день один локальный SQL-сервер выполняет синхронизацию с каким-либо связанным сервером. Следующий запрос, использующий для слияния:
MERGE [TargetDb].[dbo].[TargetTable] AS Target
USING (SELECT * FROM [RemoteServer].[SourceDb].[dbo].[TestTable]) AS Source
ON (Target.[ID] = Source.[ID])
WHEN MATCHED THEN
UPDATE SET Target.[ID] = Source.[ID],
Target.[TestFieldString] = Source.[TestFieldString],
Target.[TestFieldInt] = Source.[TestFieldInt]
WHEN NOT MATCHED BY TARGET THEN
INSERT
(ID, TestFieldString, TestFieldInt)
VALUES
(ID, Source.TestFieldString, Source.TestFieldInt);
Также на целевом сервере работает CDC
(изменить сбор данных). Смотрит на CDC
Статистика я обнаружил, что транзакция при обновлении не регистрируется в CDC
, Следующий запрос для сбора статистики:
SELECT ch.*, ch.__$seqval,
CASE ch.__$operation
WHEN 1 THEN 'delete'
WHEN 2 THEN 'insert'
WHEN 3 THEN 'prev val'
ELSE 'new val' END as operation,
map.tran_begin_time, map.tran_end_time
FROM [cdc].[dbo_TestTable_CT] ch
JOIN [cdc].[lsn_time_mapping] map
ON ch.[__$start_lsn] = map.start_lsn
ORDER BY ch.__$start_lsn, ch.__$seqval
После нескольких тестов стало ясно. Это происходит с таблицами, которые содержат первичный ключ. Если исходная таблица с PK содержит изменения, тогда выполняется запрос Merge. DELETE
а затем делать INSERT
для каждого ряда.
- Результат первого слияния в 1 ряд. Целевая таблица была пустой до этой операции.
- Обновление для
TestFieldString
в исходной таблице и результат для второго слияния в 2 и 3 строки. - Вставка новой записи в исходную таблицу и выполнение слияния. Результат для третьего слияния в 4,5,6 строки.
Это действительно странно. я жду prev val
а также new val
в колонке операций. Скрипт для создания этой таблицы выглядит следующим образом:
CREATE TABLE [dbo].[TestTable](
[ID] [uniqueidentifier] NOT NULL PRIMARY KEY,
[TestFieldString] [varchar](50) NULL,
[TestFieldInt] [int] NULL
) ON [PRIMARY]
GO
Следующий результат CDC для аналогичной таблицы без первичного ключа.
- Результат первого слияния в 1 ряд. Целевая таблица была пустой до этой операции.
- Обновление для
TestFieldString
в исходной таблице и слияния. Результат в 2 и 3 рядах. - Вставка новой записи в исходную таблицу и слияние. Результат в 4 ряду.
Это правильно CDC
результат для следующей таблицы:
CREATE TABLE [dbo].[TestTable](
[ID] [uniqueidentifier],
[TestFieldString] [varchar](50) NULL,
[TestFieldInt] [int] NULL
) ON [PRIMARY]
GO
Я читал в MSD о MERGE, но не нашел описания для этой проблемы.
Как это исправить и что не так? Может быть, это ошибка или особенность MERGE
пункт или CDC
функциональность? Это особая проблема, но для функциональности, которую я разрабатываю, это очень важная проблема.
Кроме того, перед слиянием я пытался отключить ограничения в таблице, но получил ошибку, в которой говорилось, что CDC заблокировал ограничения. Может быть, есть возможность пометить ограничения (в моем случае это первичный ключ) перед объединением и после этого получить правильный результат CDC?
Также перед слиянием запускаю следующую СП:
exec sp_MSforeachtable @command1='ALTER TABLE ? NOCHECK CONSTRAINT ALL'
И после слияния:
exec sp_MSforeachtable @command1='ALTER TABLE ? CHECK CONSTRAINT ALL'