I'm building an ASP.NET MVC5 application.
I have a DBML file representing my database (SQL Server 2008).
I have the following SQL function :
CREATE FUNCTION [dbo].[sp_GetResultsPerSubjects] (
@program VARCHAR(MAX) = NULL,
@pedagoPeriod VARCHAR(MAX) = NULL,
@intake VARCHAR(MAX) = NULL,
@acadYear VARCHAR(MAX) = NULL,
@section VARCHAR(MAX) = NULL,
@studentFilter VARCHAR(MAX) = NULL,
@moduleFilter VARCHAR(MAX) = NULL
)
RETURNS TABLE
AS
RETURN (
SELECT
A.[id],
A.[lastname],
A.[firstname],
D.[module_name],
D.[id] as [module_id],
H.[id] as [course_id],
H.[course_name],
G.[data_text]
FROM
[dbo].[Person] A
INNER JOIN [dbo].[Inscription] B ON A.[id] = B.[person_Id]
INNER JOIN [dbo].[Inscrsubject] C ON B.[id] = C.[inscription_Id]
INNER JOIN [dbo].[Module] D ON C.[id] = D.[inscrsubject_id]
INNER JOIN [dbo].[Result] E ON C.[id] = E.[inscrsubject_id]
INNER JOIN [dbo].[Note] F ON E.[id] = F.[result_id]
INNER JOIN [dbo].[Data] G ON F.[id] = G.[note_id]
INNER JOIN [dbo].[Course] H ON H.[result_id] = E.[id]
INNER JOIN [dbo].[GPS] I ON B.[gps_id] = I.[id]
WHERE
(@program IS NULL OR I.[program] IN (SELECT [Value] FROM [dbo].SplitString(@program, '|')))
AND (@pedagoPeriod IS NULL OR I.[pedagoPeriod] IN (SELECT [Value] FROM [dbo].SplitString(@pedagoPeriod, '|')))
AND (@intake IS NULL OR I.[intake] IN (SELECT [Value] FROM [dbo].SplitString(@intake, '|')))
AND (@acadYear IS NULL OR I.[acadYear] IN (SELECT [Value] FROM [dbo].SplitString(@acadYear, '|')))
AND (@section IS NULL OR I.[section] IN (SELECT [Value] FROM [dbo].SplitString(@section, '|')))
AND (@studentFilter IS NULL OR A.[id] IN (SELECT CONVERT(DECIMAL, [Value]) FROM [dbo].SplitString(@studentFilter, '|')))
AND (@moduleFilter IS NULL OR D.[id] IN (SELECT CONVERT(DECIMAL, [Value]) FROM [dbo].SplitString(@moduleFilter, '|')))
AND G.[data] = 'AVERAGE'
AND G.[data_Text] IS NOT NULL
AND G.[data_Text] <> ''
)
I call the function that way from my controller (all parameters are string) :
resultsPerSubjects = dataContext.sp_GetResultsPerSubjects(programs, pedagogicPeriods, intakes, academicYears, sections, studentSelection, moduleSelection).ToList();
I get a timeout : The wait operation timed out
Using the SQL Profiler, I see that the following query is executed :
exec sp_executesql N'
SELECT [t0].[id], [t0].[lastname], [t0].[firstname], [t0].[module_name], [t0].[module_id], [t0].[course_id], [t0].[course_name], [t0].[data_text]
FROM [dbo].[sp_GetResultsPerSubjects](@p0, @p1, @p2, @p3, @p4, @p5, @p6) AS [t0]',
N'@p0 varchar(8000), @p1 varchar(8000), @p2 varchar(8000), @p3 varchar(8000), @p4 varchar(8000), @p5 varchar(8000), @p6 varchar(8000)',
@p0='AAAA', @p1='1', @p2='a', @p3='2013-2014', @p4='F', @p5='219894352', @p6='92955'
Indeed running this query takes 12 minutes, more than the datacontext timeout.
But the strange thing is that running the function directly from SQL takes arround 1 second ! With the same parameters in the WHERE
clause :
('AAAA' IS NULL OR I.[program] IN (SELECT [Value] FROM [dbo].SplitString('AAAA', '|')))
AND ('1' IS NULL OR I.[pedagoPeriod] IN (SELECT [Value] FROM [dbo].SplitString('1', '|')))
AND ('a' IS NULL OR I.[intake] IN (SELECT [Value] FROM [dbo].SplitString('a', '|')))
AND ('2013-2014' IS NULL OR I.[acadYear] IN (SELECT [Value] FROM [dbo].SplitString('2013-2014', '|')))
AND ('f' IS NULL OR I.[section] IN (SELECT [Value] FROM [dbo].SplitString('f', '|')))
AND ('219894352' IS NULL OR A.[id] IN (SELECT CONVERT(DECIMAL, [Value]) FROM [dbo].SplitString('2319894352', '|')))
AND ('92955' IS NULL OR D.[id] IN (SELECT CONVERT(DECIMAL, [Value]) FROM [dbo].SplitString('902955', '|')))
AND G.[data] = 'AVERAGE'
AND G.[data_text] IS NOT NULL
AND G.[data_text] <> ''
If I omit the 2 last parameters, the problem disappear...
Any idea ?
EDIT :
Turning Arithabort
OFF
or ON
in SSMS does not change query execution time (still arround 1 second).
I'm not using ADO.NET or EF, but a simple LINQ to SQL DBML file.
I cannot use OPTION RECOMPILE
or OPTIMIZE FOR
as it is a function, not a stored procedure (yes I know I have named it sp_*
by error).
EDIT2 :
I'm now not sure it is a parameter sniffing problem. I tried :
- Turning
Arithabort
OFF
orON
in SSMS - Executing
EXEC sp_updatestats
to update statistics - Modifying the function to
RETURNS @t TABLE(...)
so I can declare local variables and assign parameters - Using a stored procedure instead of a function so I can use the
OPTION (RECOMPILE)
option - Using a stored procedure with parameters assignment to local variables
In all cases I still get a timeout when 2 last parameters are not null. All queries run under 2s in SSMS...
Anything else I can try ?