【发布时间】:2012-06-22 13:58:31
【问题描述】:
我有一个性能非常糟糕的存储过程。当我声明一个变量时,设置它的值,然后在 where 子句中使用它,该语句需要一个多小时才能运行。当我在 where 子句中对变量进行硬编码时,它会在不到一秒的时间内运行。
我开始通过执行计划来研究它的问题所在。看起来当我尝试将一些声明的变量传递给它时,执行计划会创建一些哈希匹配,因为它从使用 UNION 和公共表表达式的视图中选择值。
/************* 存储过程的开始 ******************/ 创建程序 GetFruit @ColorId 大整数, @SeasionId 大整数 重新编译 作为 开始 选择 一个名字 从 [Apple_View] A /* 这是下面的视图 */ INNER JOIN [水果] F 开(F.ColorId = @ColorId AND A.FruitId = F.FruitId) 在哪里 (A.ColorId = @ColorId 和 A.SeasonId = @SeasonId) 结尾 /************* 存储过程结束 **************/ /************* 视图开始 ***************/ WITH Fruits (FruitId, ColorId, SeasonId) AS ( -- 主播成员 选择 F.FruitId ,F.ColorId ,F.SeasonId 从 (( 选择不同的 EF.FruitId ,EF.ColorId ,EF.SeasonId ,EF.ParentFruitId 从 异国水果英孚 INNER JOIN水果FR ON FR.FruitId = EF.FruitId 联盟 选择不同的 SF.FruitId ,SF.ColorId ,SF.SeasonId ,SF.ParentFruitId 从 臭果SF INNER JOIN水果FR ON FR.FruitId = SF.FruitId 联盟 选择不同的 CF.FruitId ,CF.ColorId ,CF.SeasonId ,CF.ParentFruitId 从 疯狂水果CF INNER JOIN水果FR ON FR.FruitId = CF.FruitId )) F 联合所有 -- 递归父果 选择 FS.FruitId ,FS.ColorId ,FS.SeasonId ,FS.ParentFruitId 从 水果FS INNER JOIN MasterFruit MF ON MF.[ParentFruitId] = fs.[FruitId] ) 选择不同的 FS.FruitId ,FS.ColorId ,FS.SeasonId 从 水果FS /************* 视图结束 ***************/ /* 执行 */ 执行 GetFruit 1,3如果我使用设置的值运行存储过程需要一个多小时,这里是执行计划。
如果我运行存储过程删除 DECLARE 和 SET 值并将 Where 子句设置为以下语句,它将在不到一秒的时间内运行,这是执行计划:
WHERE(A.ColorId = 1 AND A.SeasonId = 3)
注意硬编码变量如何使用索引,而第一个变量使用哈希集。这是为什么?为什么 where 子句中的硬编码值与声明的变量不同?
--------这是在@user1166147的帮助下最终完成的------
我将存储过程更改为使用 sp_executesql。
创建程序 GetFruit @ColorId 大整数, @SeasionId 大整数 重新编译 作为 开始 声明 @SelectString nvarchar(max) SET @SelectString = N'SELECT 一个名字 从 [Apple_View] A /* 这是下面的视图 */ INNER JOIN [水果] F 开(F.ColorId = @ColorId AND A.FruitId = F.FruitId) 在哪里 (A.ColorId = ' + CONVERT(NVARCHAR(MAX), @ColorId) + ' 和 A.SeasonId = ' + CONVERT(NVARCHAR(MAX), @SeasonId) + ')' 执行 sp_executesql @SelectString 结尾【问题讨论】:
-
这些是变量而不是参数。 SQL Server 不进行变量嗅探,因此选择性估计将是猜测。如果添加
OPTION (RECOMPILE)会怎样? -
使用选项重新编译。有一种叫做参数嗅探的东西,sql server 根据输入值生成不同的查询计划
-
有趣的是,我没有注意到它们是局部变量。除了使用
OPTION RECOMPILE和optimize for ad hoc workloads设置之外,我过去还通过将局部变量声明移动到参数列表以及默认值来克服这个问题,从而使优化器更具可见性。 -
您可能会在dba.stackexchange.com上获得更多里程
-
很确定这只是因为疯狂的 cmets 而不是问题的质量。提供的信息很少,实际有助于解决问题,即数据的分布和真正的 SQL。恕我直言,这在当前的问题形式中无法解决,抱歉。
标签: sql sql-server tsql sql-server-2005 stored-procedures