2011-04-26 69 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