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