SQL函数调用性能奇怪的行为

时间:2015-05-07 16:13:48

标签: c# performance function linq-to-sql

我正在构建一个ASP.NET MVC5应用程序。

我有一个表示我的数据库的DBML文件(SQL Server 2008)。

我有以下SQL函数:

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] <> ''
)

我从我的控制器调用该函数(所有参数都是字符串):

resultsPerSubjects = dataContext.sp_GetResultsPerSubjects(programs, pedagogicPeriods, intakes, academicYears, sections, studentSelection, moduleSelection).ToList();

我得到超时The wait operation timed out

使用 SQL Profiler ,我看到执行了以下查询:

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'

确实运行此查询需要 12分钟,超过datacontext超时。

但奇怪的是直接从SQL运行函数需要 1秒!使用WHERE子句中的相同参数:

('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] <> ''

如果我省略最后两个参数,问题就会消失......

有什么想法吗?

编辑

在SSMS中转换Arithabort OFFON不会改变查询执行时间(仍然是1秒钟)。

我没有使用ADO.NET或EF,而是使用简单的LINQ to SQL DBML文件。

我无法使用OPTION RECOMPILEOPTIMIZE FOR,因为它是一个函数,而不是存储过程(是的,我知道我已将其命名为sp_*错误)。

EDIT2

我现在不确定这是一个参数嗅探问题。我试过了:

  1. 在SSMS中转动Arithabort OFFON
  2. 执行EXEC sp_updatestats更新统计信息
  3. 将函数修改为RETURNS @t TABLE(...),以便我可以声明局部变量并分配参数
  4. 使用存储过程而不是函数,以便我可以使用OPTION (RECOMPILE)选项
  5. 使用将参数分配给局部变量的存储过程
  6. 在所有情况下,当最后两个参数不为空时,我仍然会超时。所有查询都在SSMS中以2s运行...

    我还能尝试其他什么吗?

0 个答案:

没有答案