Исходя из плана выполнения хранимой процедуры, то, что заставляет ее выполняться медленно, - это та часть, где вы собираетесь работать с XML.
Давайте переосмыслим решение:
Я создал такую таблицу:
CREATE TABLE [Common].[EntityReference]
(
IsDeleted BIT,
ReferencedEntityType VARCHAR(100),
ReferencedEntityId VARCHAR(10)
);
GO
и манипулировал ею следующим образом (вставьте в нее записи 1М):
DECLARE @i INT = 1000000;
DECLARE @isDeleted BIT,
@ReferencedEntityType VARCHAR(100),
@ReferencedEntityId VARCHAR(10);
WHILE @i > 0
BEGIN
SET @isDeleted =(SELECT @i % 2);
SET @ReferencedEntityType = 'TEST' + CASE WHEN @i % 2 = 0 THEN '' ELSE CAST(@i % 2 AS VARCHAR(100)) END;
SET @ReferencedEntityId = CAST(@i AS VARCHAR(10));
INSERT INTO [Common].[EntityReference]
(
IsDeleted,
ReferencedEntityType,
ReferencedEntityId
)
VALUES (@isDeleted, @ReferencedEntityType, @ReferencedEntityId);
SET @i = @i - 1;
END;
позволяет проанализировать ваш код:
У вас есть ввод с разделителями-запятыми (@refEntityIds
), который вы хотите разделить, а затем выполнить запрос к этим значениям.(стоимость поддерева вашего SP на моем ПК составляет около 376). Для этого у вас есть разные подходы:
1.Передача табличной переменной в хранимую процедуру, которая содержит refEntityIds
2.ИспользуйтеФункция STRING_SPLIT для разделения строки Давайте посмотрим на пример запроса:
INSERT INTO @fake_tbl
SELECT value
FROM STRING_SPLIT(@refEntityIds, ',');
Используя это, вы получите значительное улучшение производительности вашего кода. (Стоимость поддерева: 6,19 без следующих индексов) НО эту функциюнедоступно в SQL Server 2008!
Вы можете использовать замену для этой функции (прочитайте это: https://stackoverflow.com/a/54926996/1666800) и измените свой запрос на это (стоимость поддерева по-прежнему составляет около 6,19):
INSERT INTO @fake_tbl
SELECT value FROM dbo.[fn_split_string_to_column](@refEntityIds,',')
В этом случае вы снова увидите заметное улучшение производительности.
Вы также можете создать некластеризованный индекс для таблицы [Common].[EntityReference]
, в которой немного повышение производительности тоже. Но, пожалуйста, подумайте о создании индекса, прежде чем создавать его, это может оказать негативное влияние на ваши операции DML:
CREATE NONCLUSTERED INDEX [Index Name] ON [Common].[EntityReference]
(
[IsDeleted] ASC
)
INCLUDE ([ReferencedEntityType],[ReferencedEntityId])
В случае, если у меня нет этогоindex (Предположим, что я заменил ваше раздельное решение на мое), стоимость поддерева: 6.19. Когда я добавляю вышеупомянутый индекс, стоимость поддерева снижается до 4.70, и, наконец, когда я изменяю индекс на следующий, стоимость поддерева составляет 5.16.
CREATE NONCLUSTERED INDEX [Index Name] ON [Common].[EntityReference]
(
[ReferencedEntityType] ASC,
[ReferencedEntityId] ASC
)
INCLUDE ([IsDeleted])
Благодаря @ PanagiotisKanavos следующий индекс будет работать даже лучше, чем вышеупомянутые (стоимость поддерева: 3,95):
CREATE NONCLUSTERED INDEX IX_EntityReference_ReferenceEntityID
ON Common.EntityReference (ReferencedEntityId)
INCLUDE(ReferencedEntityType)
WHERE IsDeleted =0;
Также обратите внимание, что,использование транзакции для локальной табличной переменной практически не имеет никакого эффекта, и, вероятно, вы можете просто проигнорировать ее.