【发布时间】: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,非常有趣。在我的实际情况下,“昂贵的子查询”并不是那么昂贵,所以我只是走简单的路线,因为性能损失可以忽略不计,但它激发了我的好奇心。最好记住不要总是相信执行计划来解决我猜想的最佳方法
-
如果执行计划不够聪明,无法制定出来,它可能有助于创建索引、统计信息或约束以提供足够的线索。
标签: sql sql-server short-circuiting short-circuit-evaluation