私はsp_executesql
を使用して、いくつかのパラメータで複雑な選択肢を渡しています。この方法よりも、ストアドプロシージャから取り出して変数を宣言するよりもずっと遅くなります。SQLパラメータスニッフィングは、再コンパイルが役に立たず、ローカル変数を実行する可能性があります
SQLパラメータスニッフィングについて多くの質問がありましたが、このようなケースが考えられます。しかし、DBCC FREEPROCCACHE
を呼び出すか、Option (Recompile)
で外側の選択を修正した後でも、同じクエリをストアドプロシージャの外部に書き込むのと比べて、異なる実行計画を使用します。
しかし、まだストアドプロシージャを使用していますが、パラメータのコピーをローカル変数として設定すると、効率的な実行計画が使用されます。
このシナリオでは、SQLパラメータスニッフィングが原因として除外されますか?私はクエリを再コンパイルして、それが使用している既存の実行計画がないことを確かめてください。もしそうなら、何が可能なのでしょうか?
SQLクエリーのアイデアを以下に示します(Entyフレームワークを介して生成されたような)。これは、高速クエリですが、パラメータに取り出して置く変数と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]
合流します。 EXECUTE dbo。<プロシージャ名>とRECOMPILE;を試しましたか?それがうまくいくならば、パラメータスニッフィングが問題となり、プロシージャ内で 'OPTIMIZE FOR(UNKNOWN)'クエリヒントを考慮することができます。 – jumxozizi
私は 'WITH RECOMPILE'を試して、遅い実行計画を生成しました。 OPTIMIZIE FOR(@myParam UNKNOWN)を試してみて、それは速い計画を生成しました。興味深いことに、最適化を使用して、未知数の代わりに実際の値を渡すと、遅い計画が生成されました。まだ私はこの動作を体験している理由を理解していないtho。 – user2945722
実行計画を比較して、何が起こるか把握することができます。プロシージャがコンパイルされたパラメータ値を確認することもできます。 – jumxozizi