【问题标题】:SQL Server OR condition performance issueSQL Server OR 条件性能问题
【发布时间】:2015-08-03 15:39:37
【问题描述】:

这是我的过程中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 引擎内部发生了什么?

谢谢。

【问题讨论】:

  • 获取每次运行的后执行计划(“实际执行计划”)并进行比较/对比。
  • 您可能遇到了参数嗅探问题。尝试here 解释的解决方法。
  • 感谢 cmets。 Thomas Stringer - 我比较了执行计划,但对我来说这没有意义。基本上,在这种情况下,临时表 #SearchTextListTable 将非常小。带有“OR”的执行计划表示 #SearchTextListTable 表扫描中的 40% 时间消耗,而没有“OR”的计划表示 0%。
  • 尝试将您的Where ... IN 更改为Where ... Exists,看看您的执行计划是什么样的。
  • Dynamic Search Conditions in T‑SQL 非常详细的文章,解释了内部发生的事情

标签: sql-server performance tsql


【解决方案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 中只有这一列,您还可以为这两个选项创建 2 个单独的过程,并根据具体情况从原始过程执行它们。

【讨论】:

  • 第三个选项是使用 UNion 或 UNion All 代替 OR 子句。如果您可以使用 UNION ALL,它将大大加快速度
  • 您也可以使用 If Else 语句仅运行代码的相关部分
  • @HLGEM 这并不适合联合,因为当变量中没有给出值时,OR 子句可以选择表中的所有值
  • @HLGEM 使用 if-else 可能会起作用,但存在无法为所有分支获得正确计划的风险,因为在第一次执行时为所有分支制定了查询计划,无论是否该部分将在该运行中执行或在这种情况下不执行
  • 感谢大家的 cmets 和回复。那么“SomeColumn”列实际上没有任何索引。我已经将我的 proc 转换为 IF..ELSE 并且效果很好,但我只想了解为什么 SQL 会延迟 OR...内部发生了什么?谢谢。
猜你喜欢
  • 1970-01-01
  • 2019-04-13
  • 1970-01-01
  • 2015-04-05
  • 2012-05-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多