sql-server - 为什么使用声明变量作为参数的 UDF 调用比使用硬编码参数调用快得多

标签 sql-server performance tsql user-defined-functions

在我看来,我遇到了以下非常奇怪的问题。当我按以下方式调用 UDF 时:

DECLARE @contact_id uniqueidentifier
DECLARE @group_id uniqueidentifier
SET @group_id = 'EE57E2AD-204B-4078-AFA4-11FA8375C2FD'
set @contact_id = 'E6EFCC9F-9D1C-4C38-A950-C45372F2A6D2'

SELECT COUNT( ID )  AS [CountAll] 
FROM [Document] As [Document] 
WHERE ([Document].[ID] IN (SELECT ID FROM [fs_Document_View_ee57e2ad_204b_4078_afa4_11fa8375c2fd](@contact_id, @group_id)))

它运行了 4 秒,我得到以下执行计划:fast

当我调用带有硬编码参数的 UDF 时:

SELECT COUNT( ID )  AS [CountAll] 
FROM [Document] As [Document] 
WHERE ([Document].[ID] IN (SELECT ID FROM [fs_Document_View_ee57e2ad_204b_4078_afa4_11fa8375c2fd]('E6EFCC9F-9D1C-4C38-A950-C45372F2A6D2', 'EE57E2AD-204B-4078-AFA4-11FA8375C2FD')))

我得到了这个执行计划:slow需要 91 秒。

谁能解释一下为什么会这样?

该函数调用另外 4 个嵌套函数,并向它们传递相同的参数。它与项目查看权限有关。

提前感谢您的帮助。

更新

我使用了 this article 中的选项 2| Ivan G. 提到过。

问题是参数嗅探,选项 2 解决了问题。

Another method of resolving the parameter sniffing issue is to disable parameter sniffing >altogether. This is not done with a switch or database option, but can be done from >within the script of your stored procedure code. Here is an example of how I created my >stored procedure so parameter sniffing is disabled:

DROP PROC [dbo].[DisplayBillingInfo]
GO
CREATE PROC [dbo].[DisplayBillingInfo]
  @BeginDate DATETIME,
  @EndDate DATETIME
WITH RECOMPILE
AS
DECLARE @StartDate DATETIME;
DECLARE @StopDate DATETIME;
SET @StartDate = @BeginDate;
SET @StopDate = @EndDate;
SELECT BillingDate, BillingAmt
  FROM BillingInfo
  WHERE BillingDate between @StartDate AND @StopDate; 

To disable parameter sniffing, all I did was to change the way the parameter values were used within the stored procedure. By creating two different local variables (@StartDate and @EndDate) inside my procedure, setting those variables to the passed parameters, and then using the local variables in the BETWEEN condition, I was able to disable parameter sniffing. Parameter sniffing is disabled because the optimizer is not able to identify the parameters’ values in the actual SELECT statement. Because SQL Server cannot tell what parameter values where used to call the stored procedure, the optimizer creates a generic plan based on the statistics.

When I execute my stored procedure using the code above, using either a narrow range of dates or a years’ worth of dates, the compiled execution plan always does an “index scan” operation. I can tell parameter sniff is turned off because I know that the short range of dates would normally have created an index seek operation.

最佳答案

我相信这是由于参数化。您的查询的第一个版本是参数化的,第二个不是。 “参数化的查询需要较少的重新编译,动态构建的查询需要非常频繁的编译和重新编译”(source)

对于使用参数构建的查询版本,创建执行计划然后重复使用:“如果 SQL 查询有参数,SQL Server 会创建一个为它们量身定制的执行计划以提高性能,通过一个称为“参数嗅探”的过程'。这个计划被存储和重复使用,因为它通常是最好的执行计划“(source)。

关于sql-server - 为什么使用声明变量作为参数的 UDF 调用比使用硬编码参数调用快得多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14828121/

相关文章:

sql-server - 使用sql server数据库启动liferay tomcat 6.1.1 ga2服务器

sql - 游标与 While 循环 - SQL Server

sql-server - 如何处理 XML header 中的空格?

javascript - 什么会跑得更快?

sql - JSON_MODIFY 删除数组对象

sql-server - 将 IF ...ELSE 语句添加到存储过程以跳过重复的主键

ios - 性能差异 : loadNibNamed vs. 以编程方式

c# - 比普通二进制搜索更快地搜索排序列表的自定义选项

sql - 如何获取SQL Server表结构更改的历史记录

sql-server - 插入中保留的文档中 XML 节点的顺序?