SQL性能方面,还有什么更好的:IF ... ELSE子句或WHERE LIKE子句?

时间:2008-11-05 21:13:16

标签: sql sql-server-2005 tsql

我有一个存储过程,它有一个可选参数@UserID VARCHAR(50)。问题是,有两种方法可以解决它:

  1. 给它一个默认值NULL,有一个IF...ELSE子句,执行两个不同的SELECT查询,一个'WHERE UserID = @UserID'但没有where。
  2. 为其指定默认值'%',然后让where子句使用'WHERE UserID LIKE @UserID'。在调用代码中,不会使用'%',因此只能找到完全匹配。
  3. 问题是:哪个选项更快?随着表的增长,哪个选项提供更好的性能?请注意,UserID列是外键并且未编入索引。

    编辑:根据一些答案我要添加的内容:@UserID参数不是(必然)传递的唯一可选参数。在某些情况下,有多达4或5个可选参数。

9 个答案:

答案 0 :(得分:7)

我通常做的是像

WHERE ( @UserID IS NULL OR UserID = @UserID )

为什么不编入索引?索引FK通常是一种很好的形式,因为你经常加入它们......

如果您担心查询计划存储,只需执行以下操作: 创建程序......使用RECOMPILE

答案 1 :(得分:3)

唯一可以确定的方法是实施和测量。作为参考,有第三种实现方法,这是我倾向于使用的方法:

WHERE (@UserID IS NULL OR UserId = @UserId)

答案 2 :(得分:3)

SQL Server 2005及其后续版本称为“语句级重新编译”。查看 http://www.microsoft.com/technet/prodtechnol/sql/2005/recomp.mspx

基本上,查询处理器执行的每个单独的语句都会获得自己的优化计划,然后将其存储在“计划缓存”中(这就是他们将名称从“Procedure-Cache”更改的原因)

因此,将您的T-SQL分支到单独的语句中会更好......

答案 3 :(得分:2)

为什么不使用:

where @UserID is null or UserID=@UserID 

+可维护性和性能

答案 4 :(得分:2)

只有一个存储过程的问题如上所述,SQL存储过程的编译计划,null的计划与具有值的计划完全不同。

但是,在存储过程中创建if语句将导致在运行时重新编译存储过程。这也可能会增加性能问题。

正如其他地方所提到的,这适用于测试和查看方法,考虑到if语句,@ UserID为null和两个单独的过程。

不幸的是,这些方法的速度将根据数据量和参数为空的调用频率与参数不为的调用的频率而有很大差异。同样,参数的数量也将影响需要重新编写程序的方法的功效。

如果您使用的是SQL 2005,则可能会从查询plan hint option获得一些里程数。

<强>校正: Sql 2005以及之后的“语句级重新编译”,它在一个过程中的每个语句的高速缓存中存储了单独的计划...因此,不将多个逻辑分支语句放入单个存储过程的旧的2005之前的策略不再适用。 .. - 查尔斯布雷塔纳 (我觉得这很重要,可以从评论中提升)

答案 5 :(得分:1)

我肯定会选择第一个,因为虽然它不那么“聪明”,但更容易理解发生了什么,因此更容易维护。

使用特殊含义默认值可能会在以后出现一些意想不到的副作用(有关您使用该默认值的原因的文档,并且任何维护者都可能错过它的使用)

关于效率 - 除非您关注1,000个或更多用户,否则超出维护性的问题不太可能。

答案 6 :(得分:1)

首先,如果您以此方式将其用作搜索条件,则应为UserID创建索引。

其次,比较UserID LIKE @UserID不能使用索引,因为优化器不知道您是否会给出以通配符开头的@UserID参数值。这样的值不能使用索引,因此优化器必须假定它不能使用该索引创建执行计划。

所以我建议:

  1. UserID
  2. 上创建索引
  3. 使用第一个选项WHERE UserID = @UserID,应优化该选项以使用索引。
  4. 编辑:Mark Brady提醒我,我忘了解决NULL案件。我同意Mark的回答,执行IF并执行两个查询之一。我给马克的答案+1。

答案 7 :(得分:1)

用两个替换单个存储过程。对于查询优化器来说,有很大的空间可以开始在这个问题上给你带来意想不到的后果。更改客户端代码以检测要调用的客户端代码。

我敢打赌如果你这样做了,我们就不需要这个对话了。

并在userid上添加索引。索引在那里是有原因的,就是这样。

答案 8 :(得分:0)

我会选择1,但实际上有两个存储过程。一个人将获得所有用户,一个人将获得特定用户。我认为这比传入NULL更清楚。在这种情况下,您确实需要两个不同的SQL语句,因为您要求的是不同的东西(所有行与一行)。