I am using a stored procedure to that returns a set of rows about the data in a varbinary column. I cannot, for the life of me, figure out why the query times always increase at the same rate when I use sp_executesql as opposed to exec.
Query with sp_executesql times go: <1s, 1s, 2s, 4s, 8s, 24s (etc) until, eventually, the problem “goes away” for a few minutes and the query is always ~0.006s
Query times with exec are always <500ms.
At first, I thought this was a problem with Linq2Sql, but when we ran the query Linq produces in SQL Management Studio, we got the same result.
Here’s the body of the sproc (heavily censored)
Note that the varbinary column is not being pulled
select DF.FileID,
DF.DerpFkGuid,
DF.DerpName,
DF.[FileName],
DF.FileSize as 'FileSizeBytes',
ISNULL(DFA.File_Size_Bytes_String,'Unknown') as 'FileSizeFriendly',
CONVERT(nvarchar(30),DF.FoundDate,120) as 'FileDateUploaded',
CONVERT(nvarchar(30),DF.FileDateCreated,120) as 'FileDateCreated',
CONVERT(nvarchar(30),DF.FileDateLastModified,120) as 'FileDateModified',
CASE WHEN ISNULL(dfa.Derp_ID,'00000000-0000-0000-0000-000000000000')='00000000-0000-0000-0000-000000000000' THEN 0 ELSE 1 END as 'AttachedToDerp',
ISNULL(dfa.Derp_ID,'{00000000-0000-0000-0000-000000000000}') as 'Derp_ID'
from DerpFiles DF
inner join DFDerpDerp DFdd on DFdd.DerpName = DF.DerpName
left outer join Derp_Files_Attachments dfa on dfa.FileID = DF.FileID
where WR.UserName = @UserName and DF.DuplicateFileDetected=0
Here is the code that runs consistently < 500ms
USE [DerpDatabase]
GO
DECLARE @return_value int
EXEC @return_value = [dbo].[DerpSproc]
@UserName = N'derp',
@DomainName = N'derp'
SELECT 'Return Value' = @return_value
GO
Here is the code that runs 1s ,2s ,4s, 8s , 24s, etc
declare @p5 int
set @p5=0
exec sp_executesql N'EXEC @RETURN_VALUE = [dbo].[DerpSproc]
@UserName = @p0,
@DomainName = @p1',
N'@p0 nvarchar(4000),
@p1 nvarchar(4000),
@RETURN_VALUE int output',
@p0=N'derp',
@p1=N'derp',
@RETURN_VALUE=@p5 output
select @p5
As far as I can tell, the 2 ways the sprocs are being called are essentially the same. The only difference is sp_executesql vs exec
It also appears that exec will produce the same increasing query times without the go keyword at the end. I can’t tell for sure because I don’t know if the query just happened to cache when I tried adding go?
This might be a parameter sniffing issue. Sometimes when you pass parameters into a procedure, SQL has a hard time figuring out how to use them efficiently. Try setting your parameters to local variables in the procedure, and then use the local variables in the where clause.
Parameter Sniffing