以下是我程序中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引擎内部发生了什么?
感谢。
答案 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中只有这一列,您还可以为两个选项创建两个单独的过程,并根据具体情况从原始过程执行它们。