使用参数化查询时,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 慢得多的主要内容,如果未能解决你的问题,请参考以下文章

为啥以下简单的并行化代码比 Python 中的简单循环慢得多?

使用 OR 的 SQL 查询比 2 个单独的查询慢得多

Intel 上的多线程比 AMD 慢得多

参数化sql查询语句

参数化查询

为啥在 SQL Azure 上运行查询要慢得多?