是“where(ParamID = @ParamID)OR(@ParamID = -1)”sql选择的一个好习惯

时间:2012-02-26 19:29:50

标签: sql sql-server performance filter database-performance

我曾经写过像

这样的sql语句
select * from teacher where (TeacherID = @TeacherID) OR (@TeacherID = -1)

read more

并传递@TeacherID值= -1以选择所有教师

现在我担心性能问题 你能告诉我这是一个好的做法还是坏的做法?

非常感谢

3 个答案:

答案 0 :(得分:6)

我们在存储过程中以非常有限的方式使用它。

问题是数据库引擎无法为其保留良好的查询计划。处理大量数据时,可能会对性能产生严重的负面影响。

但是,对于较小的数据集(我说不到1000条记录,但这是一个猜测)应该没问题。您必须在特定的环境中进行测试。

如果它存储在存储过程中,您可能希望包含类似WITH RECOMPILE选项的内容,以便plan is regenerated on each execution。这会(稍微)增加每次运行的时间,但是多次运行实际上可以减少平均执行时间。此外,这允许数据库检查实际查询和"short circuit"每次呼叫所需的部分。

如果您直接创建SQL并将其传递出去,那么我建议您使构建sql的部分更加智能,以便它只包含您实际需要的where子句的一部分。


您可能考虑的另一个路径是使用UNION ALL查询而不是可选参数。例如:

SELECT * FROM Teacher WHERE (TeacherId = @TeacherID)
UNION ALL
SELECT * FROM Teacher WHERE (@TeacherId = -1)

这实际上完成了同样的事情;但是,查询计划是可缓存的。我们也在一些地方使用过这种方法,并且比使用WITH RECOMPILE看到了性能提升。我们不会在任何地方都这样做,因为我们的一些查询非常复杂,而且我的性能受到打击而不是让它们进一步复杂化。

但最终,您需要进行大量测试。


这里有第二部分你应该重新考虑。 SELECT *It is ALWAYS preferable to actually name the columns you want returned并确保您返回您实际需要的那些。跨网络边界移动数据非常昂贵,只需准确指定您想要的内容,通常可以获得相当大的性能提升。此外,如果您需要的是非常有限的,您有时可以执行covering indexes,这样数据库引擎甚至不必触及基础表来获取您想要的数据。

答案 1 :(得分:6)

如果TeacherID被编入索引,并且您要将-1以外的值作为TeacherID传递以搜索特定教师的详细信息,那么此查询将最终执行全表扫描比寻求进入索引以检索特定教师的详细信息的可能更有效的选择......

...除非您使用的是SQL 2008 SP1 CU5及更高版本,否则请使用OPTION (RECOMPILE)提示。有关该主题的权威文章,请参阅Dynamic Search Conditions in T-SQL

答案 2 :(得分:3)

如果你真的担心性能,你可以分解你的程序来调用两个不同的过程:一个用于所有记录,一个用于参数。

If @TeacherID = -1
   exec proc_Get_All_Teachers
else
   exec proc_Get_Teacher_By_TeacherID @TeacherID

每一个都可以单独优化。

这是你的系统,比较性能。考虑优化最流行的选择。如果大多数用户要选择单个记录,为什么要提高他们的表现只是为了容纳所有教师(并且应该对性能有合理的期望)。

我知道单个选择查询更容易维护,但在某些时候,易于维护最终会让位于性能。