Подходы, которые позволили бы ускорить работу MERGE в SQL - PullRequest
0 голосов
/ 20 февраля 2020

Не могли бы вы порекомендовать подходы, которые позволили бы работе 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).

1 Ответ

1 голос
/ 20 февраля 2020

Я бы подумал сделать модифицированный грипп sh и заполнить, а не делать MERGE вообще.

В методе, который мне больше всего понравился, используется переключение разделов. Вы строите три одинаковые таблицы; основная таблица, из которой извлекаются пользователи, промежуточная таблица, которую вы используете для применения операций CRUD, и таблица хранения, которую вы будете использовать только в течение переходного периода после обновлений.

Для этого потребуется немного переоснащения, чтобы сдвинуть LastModified logi c прямо на CRUD операции, которые вы выполняете во время обновлений.

Затем, после того как промежуточный стол будет готов к прайм-тайму, обрежьте вчерашнюю копию удерживающего стола. Затем переключите данные из основной таблицы в пустую таблицу хранения. Переключите данные с промежуточной на главную. Вероятно, оберните все это в явную транзакцию.

Boom. Ваш стол обновлен. И у вас есть резервная копия вчерашних данных в таблице хранения, на всякий случай.

Тонны дополнительных подробностей в этих статьях:

Сравнение: переключение таблиц по сравнению с sp_rename

Почему вместо этого следует переключаться в промежуточные таблицы переименования их

...