Не могли бы вы порекомендовать подходы, которые позволили бы работе MERGE в SQL работать быстрее?
Я считаю, что вопрос касается знаний и опыта и не должен рассматриваться как основанный на мнении, поскольку все, что могло бы сделать операцию быстрее, определенно подходит для вопроса, и чем быстрее будет операция, тем лучше ответ.
В моем конкретном случае у меня есть приблизительно 1,7 миллиона записей, которые я получаю в повторяющаяся работа, и я использую записи для обновления существующих записей. Чтобы как можно меньше заблокировать реальную таблицу (это [LegalContractors]
), я использую временную таблицу (это [LegalContractorTemps]
), в которую я добавляю все записи из не SQL (но C#) код и после этого я запускаю MERGE
.
Вот что я пытаюсь:
DELETE FROM [dbo].[LegalContractorTemps] WHERE [Code] IS NULL;
DELETE FROM [dbo].[LegalContractorTemps]
WHERE [Id] IN (
SELECT [Id]
FROM [dbo].[LegalContractorTemps] [Temp]
JOIN (
SELECT [Code], [Status], MAX([Id]) as [MaxId]
FROM [dbo].[LegalContractorTemps]
GROUP BY [Code], [Status]
HAVING COUNT([Id]) > 1
) [TempGroup]
ON ([Temp].[Code] = [TempGroup].[Code] AND [Temp].[Status] = [TempGroup].[Status] AND [MaxId] != [Id])
);
CREATE UNIQUE INDEX [CodeStatus]
ON [dbo].[LegalContractorTemps] ([Code], [Status]);
SELECT GETDATE() AS [beginTime];
MERGE [dbo].[LegalContractors] AS TblTarget
USING [dbo].[LegalContractorTemps] AS TblSource
ON (TblSource.[Code] = TblTarget.[Code] AND TblSource.[Status] = TblTarget.[Status])
WHEN NOT MATCHED BY TARGET THEN
INSERT ([Code], [ShortName], [Name], [LegalAddress], [Status], [LastModified])
VALUES (TblSource.[Code], TblSource.[ShortName], TblSource.[Name], TblSource.[LegalAddress], TblSource.[Status], GETDATE())
WHEN MATCHED AND
(TblTarget.[ShortName] != TblSource.[ShortName] OR
TblTarget.[Name] != TblSource.[Name] OR
TblTarget.[LegalAddress] != TblSource.[LegalAddress]) THEN
UPDATE SET
TblTarget.[ShortName] = TblSource.[ShortName],
TblTarget.[Name] = TblSource.[Name],
TblTarget.[LegalAddress] = TblSource.[LegalAddress],
TblTarget.[LastModified] = GETDATE()
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
SELECT GETDATE() AS [endTime];
DROP INDEX [CodeStatus] ON [dbo].[LegalContractorTemps];
Прямо сейчас код, показанный выше, работает примерно 2 минуты.
Я нашел этот ответ, но я не смог применить его к своему делу, потому что мне нужно предложение WHEN NOT MATCHED
, и мне все равно придется выполнить полное сканирование (независимо от того, ни я не буду использовать MERGE
).