sp_executesql
いくつかのパラメーターで複雑な選択を渡すために使用しています。ストアド プロシージャから取り出して変数を宣言するよりも、この方法の方がはるかに時間がかかります。
SQL パラメーターのスニッフィングについて多くの質問を見てきましたが、私のシナリオはこれに当てはまるように思えます。ただしDBCC FREEPROCCACHE
、外部の Select を呼び出したり修正したりした後Option (Recompile)
でも、ストアド プロシージャの外部で同じクエリを記述する場合と比較して、別の非効率的な実行プランが使用されます。
ただし、引き続きストアド プロシージャを使用しますが、パラメーターのコピーをローカル変数として設定すると、効率的な実行プランが使用されます。
このシナリオでは、SQL パラメーターのスニッフィングが原因として除外されますか? クエリを再コンパイルするため、クエリが使用する既存の実行計画はありません。もしそうなら、この行動の他の理由として何が考えられるでしょうか?
SQLクエリのアイデアを以下に示します(エンティティフレームワークを介して生成された乱雑なもの)。これは高速なクエリですが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]