使用参数化查询时,TVF 慢得多
Posted
技术标签:
【中文标题】使用参数化查询时,TVF 慢得多【英文标题】:TVF is much slower when using parameterized query 【发布时间】:2015-06-11 22:11:07 【问题描述】:我正在尝试将内联 TVF 作为原始参数化 SQL 查询运行。
当我在 SSMS 中运行以下查询时,需要 2-3 秒
select * from dbo.history('2/1/15','1/1/15','1/31/15',2,2021,default)
我能够通过 SQL 分析器(参数化,由实体框架生成)捕获以下查询并在 SSMS 中运行它。
exec sp_executesql N'select * from dbo.history(@First,@DatedStart,@DatedEnd,@Number,@Year,default)',N'@First date,@DatedStart date,@DatedEnd date,@Maturity int,@Number decimal(10,5)',@First='2015-02-01',@DatedStart='2015-01-01',@DatedEnd='2015-01-31',@Year=2021,@Number=2
在 SSMS 中运行上述查询需要 1:08,这比非参数化版本长约 30 倍。
我尝试将option(recompile)
添加到参数化查询的末尾,但就性能而言它完全没有任何作用。这对我来说显然是一个索引问题,但我不知道如何解决它。
在查看执行计划时,似乎参数化版本大部分都挂在 Eager Spool (46%) 上,然后是 Clustered Index scan (30%) 在没有参数的执行计划中不存在。
也许我缺少一些东西,有人可以为我指出正确的方向,让我如何让这个参数化查询正常工作?
编辑:Parameterized query execution plan,non-parameterized plan
【问题讨论】:
TVF的定义是什么。你能发布计划吗? 我无法发布该功能,但它是一个将另一个 ITVF 连接到一系列日期的 ITVF。我已经在主帖中链接了这两个查询的计划。 【参考方案1】:可能是参数嗅探问题。
尝试修改您的函数,以便将参数设置为局部变量,并在 SQL 中使用局部变量而不是参数。
所以你的函数会有这样的结构
CREATE FUNCTION history(
@First Date,
@DatedStart Date,
@DatedEnd Date,
@Maturity int,
@Number decimal(10,5))
RETURNS @table TABLE (
--tabledef
)
AS
BEGIN
Declare @FirstVar Date = @First
Declare @DatedStartVar Date = @DatedStart
Declare @DatedEndVar Date = @DatedEnd
Declare @MaturityVar int = @Maturity
Declare @NumberVar decimal(10,5) = @Number
--SQL Statement which uses the local 'Var' variables and not the parameters
RETURN;
END
;
过去我也遇到过类似的问题,这是罪魁祸首,映射到局部变量会阻止 SQL Server 提出无用的执行计划。
【讨论】:
我对此进行了调查,并尝试更改参数类型。我所做的一切都没有奏效。也只是尝试了你所说的并在上面的一行中声明了所有变量,然后将每个参数设置为本地 var。这也没有改变执行计划。 @phosplait 只是检查;当您说您在上面的一行中声明了所有变量,然后将每个参数设置为本地变量。您的意思是您以与我的(新)示例类似的方式更改了函数吗?跨度> 对不起,我理解为我应该在参数调用之前声明它们。如果我错了,请纠正我,但由于它是一个内联函数,我必须将其更改为多语句函数才能执行此操作,这可能会改变执行计划。 哦,好的。我没有意识到这是一个内联函数。那么这对你没有帮助,除非如你所说,你重写为多行。 我有一个参数“报告类型”改变了我的函数的执行。像这样屏蔽这一参数会阻止 Sql Server 对两种报告类型使用原始执行计划。谢谢!以上是关于使用参数化查询时,TVF 慢得多的主要内容,如果未能解决你的问题,请参考以下文章