SQL Server OR条件性能问题

时间:2015-08-03 15:39:37

标签: sql-server performance tsql

以下是我程序中SELECT语句之一的简单版本:

select
    ...
from
    ...
where
    ((@SearchTextList IS NULL) OR 
     (SomeColumn IN (SELECT SomeRelatedColumn From #SearchTextListTable)))

@SearchTextList只是一个varchar变量,它包含以逗号分隔的字符串列表。 #SearchTextListTable是包含搜索文本值的单列临时表。

此查询需要30秒才能完成,这是我的应用程序中的性能问题。

如果我摆脱了第一个条件(即如果我删除OR条件),则只需一秒钟。

select
    ...
from
    ...
where
    SomeColumn IN (SELECT SomeRelatedColumn From #SearchTextListTable)

有人可以解释为什么会有这么大的差异吗?

SQL Server引擎内部发生了什么?

感谢。

1 个答案:

答案 0 :(得分:1)

由于您在没有指定OR时表示SQL很快,我假设该表具有SomeColumn的索引,并且#SearchTextListTable中的行数很小。在这种情况下,SQL Server可以决定使用索引来搜索行。

如果指定or子句,则查询如下:

((@SearchTextList IS NULL) OR 
 (SomeColumn IN (SELECT SomeRelatedColumn From #SearchTextListTable)))

SQL Server无法创建使用索引的计划,因为计划已缓存,并且在@SearchTextList为NULL时也必须可用。

通常有两种方法可以改进,或者使用动态SQL或者为每次执行重新编译计划。

要重新编译计划,只需将option (recompile)添加到查询的末尾即可。除非经常执行此查询,否则这应该是一个好的解决方案。缺点是它会导致CPU使用率略高,因为计划无法重复使用。

另一个选项是创建动态SQL并使用sp_executesql执行它。因为在那一点上你知道@SearchTextList是否为NULL,你可以省略SomeColumn IN ...当它不需要时。在这种情况下要注意SQL注入,不要只是将变量值连接到SQL字符串中,而是在SQL中使用变量并将它们作为sp_executesql的参数。

如果在SQL中只有这一列,您还可以为两个选项创建两个单独的过程,并根据具体情况从原始过程执行它们。