回答

3

你一定要避免使用任何custom or built-in functions wrapping a column in a filter - 它嚴重地限制了什麼優化器可以在索引使用和seekability方面爲你做。在可能的情況下,您應該習慣使用等式運算符和or/union方法,就像這裏的情況一樣。下面將通過ISNULL被更喜歡()或合併()方法:

where (
      (t.email is null) 
      or 
      (t.email = '') 
     ) 

或概述如下能夠更好地工作,以及,嘗試一下在你的環境,以確定哪個選項是最好的一個聯合的辦法。

一個簡單的例子演示了激烈的分歧,你可以在性能上看到:

use tempdb; 
go 
if object_id('tempdb..#testTable') > 0 
    drop table #testTable; 
go 
-- Build the dataset 
select top 10000000 
     cast(cast(a.name as varchar(100)) + '@' + cast(row_number() over (order by a.object_id) as varchar(15)) + '.com' as varchar(150)) as email, 
     row_number() over (order by a.object_id) as id 
into #testTable 
from sys.columns a 
cross join sys.columns b 
cross join sys.columns c 
go 
-- Create some nulls 
update #testTable 
set  email = null 
where id % 1000 = 0 
go 
-- Index 
create unique clustered index ixc__dbo_testTable__temp__nc1 on #testTable (email,id) on [default]; 
go 
set statistics io on; 
set statistics time on; 
go 
-- Try with isnull - ~cost of about 44.7 on my machine, ~2900ms to execute, and about 49,200 logical reads 
select * 
from #testTable t 
where isnull(t.email,'') = ''; 
go 
-- Try with 'or' - ~cost of about .049 on my machine, ~643ms to execute, about 31 logical reads 
select * 
from #testTable t 
where (
      (t.email is null) 
      or 
      (t.email = '') 
     ); 
go 
-- Try with union approach - ~cost of about .054 on my machine, ~751ms to execute, ~30 logical reads 
select * 
from #testTable t 
where t.email is null 
union all 
select * 
from #testTable t 
where t.email = ''; 
go 
if object_id('tempdb..#testTable') > 0 
    drop table #testTable; 
go 
+0

太棒了,我試了一下 - thx。 – Ice 2009-11-16 22:44:02

0

如果你將看到性能差異,他們會很快。

我認爲首選的風格是

ISNULL(email, '') = '' 
+0

性能差異實際上可能非常顯着 - 優化程序在優化包含函數的過濾器時不太可預測。請參閱下面的簡單測試以進行驗證。可傳播性這個術語有時用在這裏,儘管它不完全相同。 – chadhoc 2009-11-16 22:24:07