2011-04-26 48 views
2

首先让我说我完全知道sql server不会短路评估。如果由于执行计划而认为合适,“可以”,但最好不要猜测。SQL Server在这种特定情况下是否会一直短路?

我想知道,如果它可以在关于空任何特定情况下强制 - 如所有的客户在此查询

 
declare @customerId int 

set @customerId = null 
select * from customer where ((@customerId Is Null) Or [email protected]) 

客户编号动态载荷是PK(INT),不能为空

问题:有谁知道在这种情况下引擎是否总是选择左侧,或者如果我们确实最终会检查每行的右侧是否为CustomerId = null。 我猜这不能保证工作,因为右侧可能是'较少选择性',但我很好奇,如果sql服务器看到null,并知道在每种情况下这样使用左侧因为空语句。 我相信这是最好的做法,如下面的例子(如果你可以更好的查询下面请做!)但我只是好奇在这种情况下,为学习的目的,如果任何人都知道这里一致的内部行为。它适用于我所有的情况,但它也是一个主键,不可空,所以这可能是为什么这总是有效。如果它是一个可空类型,那么右边的可能会比左边的选择性更差,现在我们正在处理不同的情况。

我在这两个查询中的执行计划似乎是相同的。

反正 - 一个潜在的更好的方式来写这个(如果可以的话,请提高它)

 


declare @customerId int 
set @customerId = null 

select * from Customer 
where 

case 
    when @customerId is null then 1 
end = 1 

or 
case 
    when @customerId is not null then @customerId 
    else -1 
end = CustomerId 

这里的想法是有动态SQL解决方法 - 所以我只是想确保我知道在所有情况下。

谢谢!

回答

3

这里的主要问题不是短路。

当SQL Server编译批处理

declare @customerId int 

set @customerId = null 
select * from customer where ((@customerId Is Null) Or [email protected]) 

它不会做任何形式的“变量嗅探”的是考虑到前面的赋值语句只是对待@customerId为未知的价值。

如果您使用的是SQL Server 2008的某些版本,则可以使用OPTION(RECOMPILE)在分配变量后重新编译语句。

我建议您检阅Dynamic Search Conditions in T-SQL

+0

这似乎是一个类似的方法那篇文章工作得很好,不是吗? SELECT TOP 200 ... FROM customers WHERE(custno = @custno AND @custno IS NOT NULL) – 2011-04-27 04:01:08

+0

@Adam - 这似乎没有做同样的事情?如果'@custno为空,它不会返回任何行。如果你的列是数字的,你可以使用'WHERE custno BETWEEN COALESCE(@custno,1)和COALESCE(@custno,2147483647)'(或者根据需要调整范围,如果不仅仅是正整数) – 2011-04-27 09:56:13

+0

它的确切查询不是一回事 - 但在两种情况下,您都要比较两种情况下的客户ID = @(空),这在两种情况下都可能进行评估,因此在SQL服务器中允许这种情况非常相似,并且由于缺少短路而不会遇到问题 – 2011-04-27 17:46:24

3

你可以试试这个:

...WHERE CustomerId = COALESCE(@customerId, CustomerId) 

,或者,如果你愿意,COALESCE的 '扩展' 版本:

...WHERE CustomerId = CASE 
         WHEN @customerId IS NULL THEN CustomerId 
         ELSE @customerId 
         END 
+0

我赞成这个 - 无法将两个标记为答案 - 但是马丁也解决了主要问题。谢谢!! – 2011-04-27 04:00:37