我有一个执行非常糟糕的存储过程。当我声明一个变量时,设置它的值,然后在 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 结尾