在这种特定情况下,SQL Server 会始终短路吗?
Posted
技术标签:
【中文标题】在这种特定情况下,SQL Server 会始终短路吗?【英文标题】:Will SQL Server consistently short circuit in this specific case? 【发布时间】:2011-04-26 05:56:08 【问题描述】:首先让我说我完全知道 sql server 不会短路评估。如果由于执行计划而认为合适,它“可以”,但最好不要猜测。
我想知道是否可以在任何有关 null 的特定情况下强制它 - 例如在此查询中动态加载所有客户
声明@customerId int 设置@customerId = null select * from customer where ( (@customerId Is Null) 或 CustomerId=@customerId)CustomerId 是一个 PK (int),不能为空
问题:有谁知道在这种情况下引擎是否总是选择左侧,或者我们是否确实最终会检查每一行右侧的 CustomerId=null 是否。 我猜这不能保证有效,因为右侧可能“选择性较低”,但我很好奇 sql server 是否看到 null 并且在每种情况下都知道由于 null 而使用左侧陈述。 我相信这最好作为下面的案例 stmt 完成(如果您可以更好地执行下面的查询,请这样做!)但是如果有人知道这里有一致的内部行为,我只是出于学习目的而对这种情况感到好奇。它适用于我的所有情况,但它也是一个主键,不能为空,所以这可能就是为什么它总是有效的原因。如果它是一个可以为空的类型,那么右手边的选择性可能比左边的少,我们现在正在处理不同的情况。
我在两个查询中的执行计划似乎是相同的。
无论如何 - 一种可能更好的编写方式(如果可以,请增强它)
声明@customerId int 设置@customerId = null 从客户中选择 * 在哪里 案子 当@customerId 为空时为 1 结束 = 1 或者 案子 当@customerId 不为空时,@customerId 否则-1 结束 = 客户 ID这里的想法是为动态 sql 提供解决方法 - 所以我只是想确保我了解所有情况。
谢谢!
【问题讨论】:
【参考方案1】:这里的主要问题不是短路。
SQL Server 编译批处理时
declare @customerId int
set @customerId = null
select * from customer where ( (@customerId Is Null) Or CustomerId=@customerId)
它不做任何考虑到前面赋值语句的“变量嗅探”,它只是将@customerId
的值视为未知。
如果您使用的是(某些版本的)SQL Server 2008,您可以使用OPTION(RECOMPILE)
在分配变量后让它重新编译语句。
我建议查看Dynamic Search Conditions in T-SQL
【讨论】:
那篇文章中的类似方法似乎效果很好,不是吗?选择 TOP 200 ... 从客户那里(custno = @custno AND @custno 不为空) @Adam - 这似乎没有做同样的事情?如果@custno is null
不会返回任何行。如果您的列是数字,您可以使用WHERE custno BETWEEN COALESCE(@custno, 1) AND COALESCE(@custno, 2147483647)
(或者如果不仅仅是正整数,则根据需要调整范围)
它的确切查询不是一回事 - 但在这两种情况下,您都在比较 CustomerId=@(null) 可能在两种情况下评估的相同概念,因此在这方面非常相似在 sql server 中是允许的,并且不会因为缺少短路而遇到问题【参考方案2】:
你可以试试这个:
...WHERE CustomerId = COALESCE(@customerId, CustomerId)
或者,如果您愿意,可以使用 COALESCE 的“扩展”版本:
...WHERE CustomerId = CASE
WHEN @customerId IS NULL THEN CustomerId
ELSE @customerId
END
【讨论】:
我对此表示赞同——无法将两个标记为答案——但马丁也解决了主要问题。谢谢!!以上是关于在这种特定情况下,SQL Server 会始终短路吗?的主要内容,如果未能解决你的问题,请参考以下文章
在这种特定情况下,如何使用 SQL 仅检索与日期字段的最后一个值相关的记录?
我可以在不中断复制的情况下从 SQL Server 复制订阅者数据库中删除特定数据吗?