存储过程中的IF/ELSE性能

4
我找到了一篇文章,解释了在存储过程中使用IF/ELSE语句会导致性能下降,与之相比,针对每个“分支”使用单独的存储过程可以提高性能。http://sqlmag.com/t-sql/if-statements-and-stored-procedure-performance 但是,我有一个存储过程,选取相同的列、相同的表,只有WHERE子句因变量不同而变化。以下是一个例子:
IF @Variable1 IS NOT NULL 
 BEGIN
   SELECT 
        *
   FROM
     dbo.Table1
   WHERE
     Column1 = @Variable1
  END
ELSE IF @Variable1 IS NULL AND @Variable2 IS NOT NULL
 BEGIN
  SELECT 
   *
  FROM
   dbo.Table1
  WHERE
   Column1 = Column1 
   AND
   Column2 = @Variable2
 END
在这个例子中,是将2个不同的变量分别处理放在两个存储过程中更好,还是像这样全部放在一个存储过程中?(我知道使用SELECT *不是好的实践方式,我只是为了举例而已)

3
该文章来自SQL Server 2000版本为当前版本的时期。自那时以来发生了很多变化,包括优化器方面的巨大改进。我建议从Column1 = COALESCE(@Variable1, Column1) AND Column2 = COALESCE(@Variable2, Column2)开始,然后进一步进行优化(例如使用OPTION (RECOMPILE)或动态SQL),如果你发现同样的参数被多个变量使用导致性能问题时。当处理变得更加复杂时,我开始称之为“万能方法”,并退回到与optimize for ad hoc workloads结合使用的动态SQL。 - Aaron Bertrand
1个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
4

通常情况下,我不会担心这个问题,但是你应该查看Mikael Eriksson引用的白皮书,其中包含大量有关此主题的有用信息。然而,我建议在else分支中删除Column1 = Column1语句,因为那可能会使优化器混淆。

文章所指的是存储过程在第一次运行时编译。这可能会产生不好的结果。例如,如果在首次调用时表为空,则优化器可能更喜欢全表扫描而不是索引查找,而随着表格变得越来越大,这将是不好的。

问题可能是其中一个分支获得了次优的性能计划,因为数据在第一次调用时并不典型。特别是如果其中一个值为NULL。这不仅发生在if中,但这是一个需要注意此问题的情况。

我建议以下几点:

  • 如果您的表格会随时间增长/缩小,请定期重新编译您的存储过程。
  • 如果您的表格代表了数据,请不要担心将其拆分为多个存储过程。
  • 您的示例应该执行索引查找,这相当简单。但是要监视性能并检查执行计划以确保它们是您想要的。
  • 如果您想强制使用索引,可以使用提示。(就我个人而言,我需要提示来强制使用特定的连接算法,但不是索引使用,但我相信其他人可能有不同的经验。)

对于您的示例,table1(column1)table1(column2)上的索引应该足够了。

建议的摘要是在看到问题之前不要去修复它。将逻辑放入两个存储过程中应该是为了解决实际存在的问题,而不是预防可能永远不会出现的问题。如果您确实采用了双存储过程方法,则仍然可以拥有调用每个存储过程的单个接口,因此您仍然具有相同的API。换句话说,一个存储过程应该变成三个而不是两个。


向表中添加索引将导致重新编译使用该表的查询。在存储过程中,这将作为语句级别的重新编译完成,只编译需要重新编译的部分。修改表也将(最终)导致重新编译,但可能不像您希望的那样频繁。SQL Server中的计划缓存 - Mikael Eriksson
1
@MikaelEriksson……你是正确的。我修正了答案以符合您的正确观察,并强调了我想要表达的重点。 - Gordon Linoff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,