如果不需要,SQL Server 是不是足够聪明,不会执行昂贵的查询? (短路)
Posted
技术标签:
【中文标题】如果不需要,SQL Server 是不是足够聪明,不会执行昂贵的查询? (短路)【英文标题】:Will SQL Server be smart enough to not execute expensive queries if it is not needed ? (short-circuiting)如果不需要,SQL Server 是否足够聪明,不会执行昂贵的查询? (短路) 【发布时间】:2020-08-06 14:28:13 【问题描述】:因此,SQL Server 不会像通用编程语言中的 if 语句那样以显式方式进行短路。
因此考虑以下模拟查询:
SELECT * FROM someTable
WHERE name = 'someValue' OR name in (*some extremely expensive nested sub-query only needed to cover 0.01% of cases*)
假设表中只有 3 行,并且所有行都匹配 name = 'someValue'。昂贵的子查询会运行吗? 假设有 300 万行,除了 1 之外的所有行都可以使用 name = 'someValue' 获取,但需要使用子查询获取的 1 行除外。不需要时是否会评估子查询?
如果有人有类似的真实案例,只要在没有 99.99% 的子查询的情况下快速获取结果,就可以让 0.01% 的人等待昂贵的子查询运行后再获得结果的案例。 (我知道我上面的具体示例可以使用 SP 中的 IF 语句显式处理,正如此相关线程中所建议的: Sql short circuit OR or conditional exists in where clause 但让我们假设这不是一个选项。)
【问题讨论】:
SQL 布尔运算符不保证短路,也不保证不短路。优化器可能会或可能不会根据执行计划的最终结果而忽略子句,而这又取决于许多其他因素,因此没有简单的答案。原则上,就语义而言,您必须假设它们不会短路。使用CASE
比布尔运算符更可靠,但也不能 100% 保证省略不必要的子句(但仍然更加一致)。如果您需要性能,这可能是更好的选择。
您可能会争辩说,当所有行都相等someValue
时,不需要子查询,但即使不是,它也是需要的。如果你说你至少有一行不等于someValue
,那么是的,它需要被执行,没有办法绕过它。无论如何,当所有行都是someValue
时,它很可能会被执行。如果它必须保留一个查询,请将其两个查询,= 'someValue'
和<> 'someValue' and (expensive)
和union all
的结果合二为一。但这仍然不能保证。
FWIW,我在您的问题中运行了代码,其中子查询引用了一个没有有用索引的大表。大表从未接触过 3 行“someValue”,因为该计划包含一个启动表达式过滤器以进行短路。 YMMV 取决于许多因素,因此无法一概而论。
@DanGuzman 感谢所有的 cmets,非常有趣。在我的实际情况下,“昂贵的子查询”并不是那么昂贵,所以我只是走简单的路线,因为性能损失可以忽略不计,但它激发了我的好奇心。最好记住不要总是相信执行计划来解决我猜想的最佳方法
如果执行计划不够聪明,无法制定出来,它可能有助于创建索引、统计信息或约束以提供足够的线索。
【参考方案1】:
正如 cmets 所指出的,SQL Server 中的优化器非常聪明。
您可以使用case
尝试短路。正如documentation 所说:
CASE
表达式按顺序计算其条件,并在满足条件的第一个条件处停止。
请注意,有一些涉及聚合的例外情况。所以,你可以这样做:
SELECT t.*
FROM someTable t
WHERE 'true' = (CASE WHEN t.name = 'someValue' THEN 'true'
WHEN t.name in (*some extremely expensive nested sub-query only needed to cover 0.01% of cases*)
THEN 'true'
END)
这种强制排序通常被认为是一个坏主意。一个例外是其中一条路径可能涉及错误,例如类型转换错误)——但是,现在通常使用 try_
函数解决此问题。
在您的情况下,我怀疑用EXISTS
替换IN
并使用适当的索引可能会消除子查询的几乎所有性能损失。但是,那是另一回事。
【讨论】:
以上是关于如果不需要,SQL Server 是不是足够聪明,不会执行昂贵的查询? (短路)的主要内容,如果未能解决你的问题,请参考以下文章
RestKit / Core Data / Offline - 我需要 UUID 还是 RestKit 足够聪明?