Обнаружение параметров SQL возможно, что перекомпиляция не помогает, но локальные переменные делают
Я использую sp_executesql
пройти сложный выбор с несколькими параметрами. Делать это намного медленнее, чем извлекать из хранимой процедуры и объявлять переменные.
Я видел много вопросов о сниффинге параметров SQL, и мой сценарий звучит так. Однако даже после звонка DBCC FREEPROCCACHE
или внесение поправок в внешний Select с помощью Option (Recompile)
он по-прежнему использует другой и неэффективный план выполнения по сравнению с написанием того же запроса вне хранимой процедуры.
Однако все еще используется хранимая процедура, но при настройке копий параметров в качестве локальных переменных будет использоваться эффективный план выполнения.
Этот сценарий исключает использование параметра SQL в качестве причины? Потому что я перекомпилирую запрос, конечно, нет никакого ранее существующего плана выполнения, который он использует. Если да, то какие могут быть другие причины такого поведения?
Просто чтобы дать вам представление о SQL-запросе, вы можете увидеть его ниже (Messy, сгенерированный через Entity Framework). Это быстрый запрос, но при вводе в sp_executesql
proc с переменной, извлеченной и вставленной в параметры, генерирует неэффективный план выполнения
DECLARE @p__linq__0 INT = 2032
,@p__linq__1 UNIQUEIDENTIFIER = '8CC161FC-B8DE-4746-BA4F-62FA55DF26DE'
,@p__linq__2 uniqueidentifier= '8CC161FC-B8DE-4746-BA4F-62FA55DF26DE',
@p__linq__3 uniqueidentifier= '8CC161FC-B8DE-4746-BA4F-62FA55DF26DE',
@p__linq__4 uniqueidentifier= '8CC161FC-B8DE-4746-BA4F-62FA55DF26DE',
@p__linq__5 INT = 6771
SELECT
[Limit1].[UserIdValue] AS [UserIdValue]
FROM (SELECT [Extent1].[Id] AS [Id]
FROM [dbo].[Request] AS [Extent1]
WHERE ([Extent1].[InstanceId] = @p__linq__0) AND ([Extent1].[DeletedDate] IS NULL) AND (( EXISTS (SELECT
1 AS [C1]
FROM ( SELECT
[Extent2].[TeamId] AS [TeamId],
[Extent2].[HasUpdateAccess] AS [HasUpdateAccess]
FROM [dbo].[RequestTypeTeam] AS [Extent2]
WHERE [Extent1].[RequestTypeId] = [Extent2].[RequestTypeId]
) AS [Project1]
WHERE ([Project1].[HasUpdateAccess] = 1) AND ( EXISTS (SELECT
1 AS [C1]
FROM [dbo].[UserTeam] AS [Extent3]
WHERE ([Project1].[TeamId] = [Extent3].[TeamId]) AND ([Extent3].[UserId] = @p__linq__1)
))
)) OR (([Extent1].[InsertUserId] = @p__linq__2) AND ( EXISTS (SELECT
1 AS [C1]
FROM ( SELECT
[Extent4].[TeamId] AS [TeamId],
[Extent4].[HasCreatorAccess] AS [HasCreatorAccess]
FROM [dbo].[RequestTypeTeam] AS [Extent4]
WHERE [Extent1].[RequestTypeId] = [Extent4].[RequestTypeId]
) AS [Project4]
WHERE ([Project4].[HasCreatorAccess] = 1) AND ( EXISTS (SELECT
1 AS [C1]
FROM [dbo].[UserTeam] AS [Extent5]
WHERE ([Project4].[TeamId] = [Extent5].[TeamId]) AND ([Extent5].[UserId] = @p__linq__3)
))
))) OR ( EXISTS (SELECT
1 AS [C1]
FROM [dbo].[RequestTeam] AS [Extent6]
WHERE ([Extent1].[Id] = [Extent6].[RequestId]) AND ([Extent6].[TeamId] IN (3147, 3165))
)) OR ( EXISTS (SELECT
1 AS [C1]
FROM ( SELECT
(SELECT
COUNT(1) AS [A1]
FROM [dbo].[RequestControlData] AS [Extent8]
WHERE ([Project8].[Id] = [Extent8].[ControlId]) AND ([Extent8].[RequestId] = [Extent1].[Id]) AND ([Extent8].[UserIdValue] = @p__linq__4)) AS [C1]
FROM ( SELECT
[Extent7].[Id] AS [Id]
FROM [dbo].[Control] AS [Extent7]
WHERE ([Extent7].[RequestTypeId] IS NOT NULL) AND ([Extent1].[RequestTypeId] = [Extent7].[RequestTypeId]) AND ([Extent7].[DeletedDate] IS NULL) AND ([Extent7].[IsAuthorisation] = 1)
) AS [Project8]
) AS [Project9]
WHERE [Project9].[C1] > 0
))) AND ( NOT ([Extent1].[StatusId] IN (1071))) AND ( NOT ([Extent1].[RequestTypeId] IN (1215)))) AS [Filter11]
OUTER APPLY (SELECT TOP (1)
[Extent9].[ControlId] AS [ControlId],
[Extent9].[UserIdValue] AS [UserIdValue],
[Extent10].[Id] AS [Id],
[Extent10].[SharedControlId] AS [SharedControlId]
FROM [dbo].[RequestControlData] AS [Extent9]
INNER JOIN [dbo].[Control] AS [Extent10] ON [Extent9].[ControlId] = [Extent10].[Id]
WHERE ([Filter11].[Id] = [Extent9].[RequestId]) AND (([Extent10].[SharedControlId] = @p__linq__5) OR (([Extent10].[SharedControlId] IS NULL) AND (@p__linq__5 IS NULL
)))
)
AS [Limit1]
2 ответа
Снова столкнулся с той же проблемой и хотел опубликовать ответ, который работал для меня.
Я побежал UPDATE STATISTICS [TableName] WITH FULLSCAN
в различных таблицах, относящихся к моему запросу, после этого он работал так же быстро, как и при использовании локальных переменных.
Интересно отметить, что без WITH FULLSCAN
это все равно будет медленно. Кроме того, после обновления статистики был быстрый первый запуск, а затем медленный следующий запуск, поэтому мне пришлось постоянно обновлять статистику, чтобы заставить ее работать быстро, затем я попытался обновить статистику, выполнить запрос (был быстрый запуск), а затем призвание DBCC FREEPROCCACHE
и это, казалось, это исправить, так что это было быстро каждый раз, когда я запускал его
Я предполагаю, что это означает, что проблема была не в прослушивании параметров.
Я думаю, что ваша проблема с дизайном, а не с данными, несколько подзапросов дороже, особенно с оператором ИЛИ
Я бы лучше использовал несколько табличных переменных и оставил внешние объединения