【问题标题】:Why doesn't sql short circuit where conditions为什么sql不会短路where条件
【发布时间】:2015-09-22 23:27:05
【问题描述】:

我有一个 sql proc,其中一些 where 条件看起来像这样:

AND (@p1 is null OR @p1 like '%' + cast(f1 as varchar(max)) + '%')

显然,这是为了允许用户根据需要按特定参数进行过滤,或者不过滤他们传入的 null。我今天在尝试调试查询时注意到的一件奇怪的事情是,当我将此行注释掉时,即使@p1 为空,查询的运行速度也会大大加快。

如果@p1 为空,我希望 SQL 足够聪明,可以忽略其他 OR 条件。我在这里做错了什么还是有更好的方法来实现这一点,以便在满足第一个 OR 条件时 SQL 不会浪费时间处理额外的 OR 条件?还是有一个我不明白的基本问题是关于 SQL 如何检索阻止它这样做的数据?

【问题讨论】:

  • 如果要提高性能,可以在查询后使用OPTION(RECOMPILE)。 SQL Server 根据参数新值重新编译查询时间。
  • 这种情况下动态生成的 SQL 会提高性能。如果@p1 为空,则完全排除该条件。假设您有许多这些条件,将 SQL 修改为您需要检查的内容会更有效。
  • 一般来说,因为编译查询的成本很高,所以会创建一个返回正确结果的计划无论变量的值是什么,并且该计划会被重用。因此,该计划至少必须至少访问具有 f1 字段的表或索引,如果您完全删除该子句,它可以可能生成使用不包含 f1 的索引的计划。要更快。您必须查看计划以了解它们有何不同。
  • 我认为这里的任何人都无法比this article by Gail Shaw 更好地回答您的问题。说真的,那太好了。
  • @DMason +1 无论如何都是极好的链接。

标签: sql sql-server-2012


【解决方案1】:

执行计划基于查询,创建计划时不考虑@p1的实际值(或至少不认为是计划将用于的唯一值)。

如果数据库决定条件应该被短路,那么即使条件的第二部分可以使用索引并更有效地消除记录,它也必须实际评估每条记录的条件。

通常,查询被转换为通常比为每条记录评估表达式更有效的东西。但是,对于某些特定值,这可能会降低效率。

【讨论】:

  • 对此我有 2 条回复。第一个:作为实施问题,这“可能”是真的(我不知道它是真的)。但从逻辑上讲,事实并非如此。没有理由不能告诉 @p1 将为每条记录保存相同的值,因此只需要评估一次。
  • 第二个响应:好的,那么为什么它看不到评估空值检查比评估类似模式要快得多?我很满意它必须评估每条记录上的 null 检查,因为这非常快。
  • 很抱歉,不要试图过于相反,但是当我看到 SQL 可以进行的所有其他更复杂的优化时,这些答案并不完全让我满意,因为这是一个非常简单的计算进行比较。
  • @BVernon:您认为表达式是应该被评估的东西,但查询规划器并没有这样做。它不认为表达式应该短路或不短路,它把整个查询从里到外变成完全不同的东西,试图找到最有效的方法来找到结果。即使空值检查对某个特定值有效,但仍有大量值无用。
  • 我知道 SQL 不需要短路,但你让它听起来好像永远不会发生。它不查看索引并据此决定操作的顺序吗?我想我想了解这有什么不同。
【解决方案2】:

因为 SQL 是声明式的,而不是过程式的。因此,执行顺序不受用户控制,也不受编写语句的顺序指示。您描述您想要什么,RDBMS 决定如何最好地满足您的要求。

【讨论】:

  • 我确实知道。更具体地说,我应该问为什么 SQL 不够聪明,无法在这种情况下选择在第一个条件下运行,如果它实际上首先在第一个条件下运行,那么为什么它也在第二个条件下运行?
  • 或者更简单地说:为什么 RDBMS 不决定以更有效的方式满足我的请求? :)
  • @BVernon 这可能是由于各种原因,包括parameter sniffinggeneral nature of your query
猜你喜欢
  • 2012-11-18
  • 1970-01-01
  • 2021-06-03
  • 1970-01-01
  • 2019-12-12
  • 2014-05-19
  • 1970-01-01
  • 2016-10-27
  • 2011-03-25
相关资源
最近更新 更多