Sql 为什么我的存储过程不考虑条件逻辑而执行所有选择?

Sql 为什么我的存储过程不考虑条件逻辑而执行所有选择?,sql,sql-server-2008,stored-procedures,logic,Sql,Sql Server 2008,Stored Procedures,Logic,我正在使用SQLServer2008 我有一个有趣的场景,在这个场景中,如果主表中有数据,则存储过程(由“超级用户”编写)的正常运行时间为(大约4秒)。如果搜索值不存在,则运行时间平均约为3分钟。由于该过程的工作方式以及使用该过程的web应用程序,在没有数据的情况下需要一个空的结果集 我已经用包含数据的值和不包含数据的值测试了下面的逻辑,并且流程似乎正常工作;然而,当我将实际查询放在else语句中时,尽管我知道逻辑分支不应该执行,但该部分似乎总是在被计算 DECLARE @spId int S

我正在使用SQLServer2008

我有一个有趣的场景,在这个场景中,如果主表中有数据,则存储过程(由“超级用户”编写)的正常运行时间为(大约4秒)。如果搜索值不存在,则运行时间平均约为3分钟。由于该过程的工作方式以及使用该过程的web应用程序,在没有数据的情况下需要一个空的结果集

我已经用包含数据的值和不包含数据的值测试了下面的逻辑,并且流程似乎正常工作;然而,当我将实际查询放在else语句中时,尽管我知道逻辑分支不应该执行,但该部分似乎总是在被计算

DECLARE @spId int

SELECT @spId = td.mainId
FROM dbo.PRIMARYTABLE
WHERE td.longId = @searchVal

IF @spId < 1 OR @spId IS NULL
BEGIN
     select 'RETURN EMPTY RESULT SET' as test
END
ELSE 
BEGIN
    SELECT 'DO ACTUAL QUERY' as test
END
DECLARE@spId int
选择@spId=td.mainId
来自dbo.PRIMARYTABLE
其中td.longId=@searchVal
如果@spId<1或@spId为空
开始
选择“返回空结果集”作为测试
结束
其他的
开始
选择“执行实际查询”作为测试
结束
当我用一个伪值(比如1111)来测试它时,返回选择“returnempty RESULT SET”作为测试。当我使用一个我知道存在的值时,返回SELECT'DO ACTUAL QUERY'作为测试。当我将“SELECT'DO ACTUAL QUERY'as test”替换为实际的重载查询并使用相同的不存在的伪值时,看起来仍然达到了ELSE子句


我在这里错过了什么?

也许你没有展示所有的东西。select中的赋值有一个与直觉相反的地方,即不返回任何行—变量的值不会被清除。将其粘贴到SSMS中:

declare @searchVal as int
set @searchVal=111

DECLARE @spId int
set @spId = 2134
SELECT @spId = td.mainId
FROM (select 839 as mainId, 0 as longid) td
where td.longId = @searchVal
print @spid
@spid将是2134。这就是为什么在您的情况下,应该始终使用@rowcount进行测试的原因

IF @@rowcount = 0 or @spId < 1 or @spId is null
BEGIN
    select 'RETURN EMPTY RESULT SET' as test
END
ELSE 
BEGIN
    SELECT 'DO ACTUAL QUERY' as test
END
如果@rowcount=0或@spId<1或@spId为空
开始
选择“返回空结果集”作为测试
结束
其他的
开始
选择“执行实际查询”作为测试
结束
也有可能通过longId复制数据,从满足@searchval条件的行返回随机mainid


除此之外,我不知道。

谢谢大家的建议。我很抱歉没有发布整个存储过程,但我不允许共享确切的代码。我开始使用的代码片段是psuedo代码(好吧,是重命名了表和字段的真实代码)

我认为尼古拉·马尔科维诺维奇的答案和文章链接可能有点问题。这整个折磨有点让人发疯。我在谷歌上搜索、调试,然后再做一遍,然后搜索堆栈溢出。在对您的建议进行了一些更改之后,该过程神奇地开始以我认为应该的运行时间响应。我不认为最初的一些更改发生了,或者sql server没有正确缓存这些更改;我只有猜测

这是非常奇怪的,因为在一个小时或更长的时间里,它一直在运行,就好像它从未被改变过一样(从性能上看)…然后它就启动了。我想知道这是否是我的错,也许我没有像在测试中那样改变舞台上的那个……这似乎是最可行的解释


无论如何,谢谢你的建议。我学到了一些东西,所以总是好的。

你说“看起来像”,所以你不确定?另外,您的“繁重”问题是什么?您发布的代码不完整(例如缺少别名、变量声明),因此可能是您对“重载”查询做了一些不同的操作。我怀疑你是否用不满意的标准击中了ELSE子句“重载”查询是一个怪物,在许多计算中始终使用强制转换、舍入和IsNulls。我不知道是否有我不熟悉的Sql Server存储过程机制,但在我的测试中,if/else条件逻辑似乎很合理;然而,似乎从代码执行时仍会调用else部分(通过sql management studio或asp.net mvc web应用程序)。仅将“轻量级”选择替换为“havy duty”不会改变IF…else流。最有可能是您的IF条件(read@spId变量)获得了“意外值”。尼古拉的回答可以为你提供一个很好的起点。最后一件事是认为使用@spId<1或null,您可以以某种方式命中ELSE块。在声明@spId后,我将其默认为0,并将@rowcount添加到条件中。我添加了打印语句,并在SQLServerManagementStudio中执行了存储过程的核心部分。这很奇怪。正在执行正确的逻辑分支;然而,这种逻辑只不过是(相当字面地)选择“作为col1”、“作为col2”和“作为col3”。在第二种情况下自行执行;这应该是一件几乎没有成本的事情;但是,运行仍然需要大约3分钟,这就是当给定一个不存在的searchVal时,大查询所需的时间。我在这里完全不知所措。对不起。。。我想请你把所有的东西(代码)都贴在这里。例如,“嘿,这段代码……工作正常”和“这段代码……不工作。为什么?”。将select更改为
select@spId=max(td.MainId)
也会工作,因为这样会始终返回一行,如果找不到匹配的记录,则返回null。如果
longId
具有唯一约束,则SQL Server应生成一个计划,该计划通过关联索引查找一个值。