【发布时间】:2019-09-30 13:03:16
【问题描述】:
我正在调查 SQL Server 中内联表函数的执行速度问题。或者这就是我认为问题所在。我遇到了
T-SQL code is extremely slow when saved as an Inline Table-valued Function
这看起来很有希望,因为它描述了我所看到的,但我似乎遇到了相反的问题 - 当我将变量传递给我的函数时,需要 17 秒,但是当我在查询窗口中运行我的函数代码时,对变量使用 DECLARE 语句(我认为这有效地使它们成为文字),它以毫秒为单位运行。相同的代码,相同的参数 - 只是将它们包装在一个内联表函数中似乎会拖累它。
我试图将我的查询减少到仍然表现出该行为的尽可能少的代码。我正在使用许多现有的内联表函数(所有这些函数多年来都运行良好),并设法将我的代码精简为只需要调用一个现有的内联表函数即可突出显示速度差异。但在这样做的过程中,我注意到了一些非常奇怪的事情
SELECT strStudentNumber
FROM dbo.udfNominalSnapshot('2019', 'REG')
需要 17 秒,而
DECLARE @strAcademicSessionStart varchar(4) = '2019'
DECLARE @strProgressCode varchar(12)= 'REG'
SELECT strStudentNumber
FROM dbo.udfNominalSnapshot(@strAcademicSessionStart, @strProgressCode)
需要几毫秒!因此,与将代码包装在内联表函数中无关,而是与如何将参数传递给其中的嵌套函数有关。根据引用的文章,我猜测有两种不同的执行计划在起作用,但我不知道为什么/如何,更重要的是,我能做些什么来说服 SQL Server 使用高效的?
附:这是响应评论请求的内部 UDF 调用的代码
ALTER FUNCTION [dbo].[udfNominalSnapshot]
(
@strAcademicSessionStart varchar(4)='%',
@strProgressCode varchar(10)='%'
)
RETURNS TABLE
AS
RETURN
(
SELECT TOP 100 PERCENT S.strStudentNumber, S.strSurname, S.strForenames, S.strTitle, S.strPreviousSurname, S.dtmDoB, S.strGender, S.strMaritalStatus,
S.strResidencyCode, S.strNationalityCode, S.strHESAnumber, S.strSLCnumber, S.strPreviousSchoolName, S.strPreviousSchoolCode,
S.strPreviousSchoolType,
COLLEGE_EMAIL.strEmailAddress AS strEmailAlias,
PERSONAL_EMAIL.strEmailAddress AS strPersonalEmail,
P.[str(Sub)Plan], P.intYearOfCourse, P.strProgressCode,
P.strAcademicSessionStart, strC2Knumber AS C2K_ID, AcadPlan, strC2KmailAlias
,ISNULL([strC2KmailAlias], [strC2Knumber]) + '@c2kni.net' AS strC2KmailAddress
FROM dbo.tblStudents AS S
LEFT JOIN
dbo.udfMostRecentEmail('COLLEGE') AS COLLEGE_EMAIL ON S.strStudentNumber = COLLEGE_EMAIL.strStudentNumber
LEFT JOIN
dbo.udfMostRecentEmail('PERSONAL') AS PERSONAL_EMAIL ON S.strStudentNumber = PERSONAL_EMAIL.strStudentNumber
INNER JOIN
dbo.udfProgressHistory(@strAcademicSessionStart) AS P ON S.strStudentNumber = P.strStudentNumber
WHERE (P.strProgressCode LIKE @strProgressCode OR (SUBSTRING(@strProgressCode, 1, 1) = '^' AND P.strProgressCode NOT LIKE SUBSTRING(@strProgressCode, 2, LEN(@strProgressCode)))) AND
(P.strStudentNumber NOT IN
(SELECT strStudentNumber
FROM dbo.tblPilgrims
WHERE (strAcademicSessionStart = @strAcademicSessionStart) AND (strScheme = 'BEI')))
ORDER BY P.[str(Sub)Plan], P.intYearOfCourse, S.strSurname
)
【问题讨论】:
-
是
varchar(4) = 2019还是int = 2019? -
您查看过这两个查询的执行计划了吗?除非您使用强制参数,否则 SQL 服务器会为一个查询缓存多个计划并不少见。这也可能是参数嗅探问题。请看以下链接:brentozar.com/sql/parameter-sniffing
-
值 2019 是一个 varchar,我想它应该用引号引起来,但 SQL 似乎很高兴,在慢速版本中将它引用为 '2019' 并没有任何区别
-
也可以分享一下功能吗?
-
你能把计划贴在这里brentozar.com/pastetheplan吗?并在这里分享?
标签: sql-server sql-execution-plan