2011-09-08 74 views
5

我發現,在某些情況下,像SQL服務器加入VS子查詢的性能問題

select 
    usertable.userid, 
    (select top 1 name from nametable where userid = usertable.userid) as name 
from usertable 
where active = 1 

查詢所需的數量級不再SS2008R2完成比同等聯接查詢

select 
    usertable.userid, 
    nametable.name 
from usertable 
left join nametable on nametable.userid = usertable.userid 
where usertable.active = 1 

其中兩個表索引並有超過10萬行。有趣的是,插入頂部條款列入原始查詢使得它看齊聯接查詢執行:

select 
    top (select count(*) from usertable where active = 1) usertable.userid, 
    (select top 1 name from nametable where userid = usertable.userid) as name 
from usertable 
where active = 1 

沒有人有任何想法,爲什麼原來的查詢執行如此糟糕?

+3

FYI診斷性能問題時,你應該總是讓查詢執行計劃。 – Justin

+0

如果您有權訪問Safari Books Online,請參閱「InsideMicrosoft®SQL Server 2005:查詢優化和優化 - 第3章」或另一個好鏈接http://blogs.msdn.com/b/craigfr/archive/2006 /09/27/774107.aspx –

回答

3

那麼,查詢是不同的 - 除非userid列是主鍵或具有唯一性約束,那麼第二個查詢可能會返回比第一個更多的行。

也就是說,在假設用戶ID是主鍵/唯一嘗試刪除第一子查詢的TOP 1部分:

select 
    usertable.userid, 
    (select name from nametable where userid = usertable.userid) as name 
from usertable 
where active = 1 
+0

這完全是訣竅。因爲查詢是在運行中生成的,所以我將它作爲預防措施避免運行時錯誤。現在我需要弄清楚我是否可以安全地將其作爲一般規則刪除。 –

2

這是一個相關的子查詢,這意味着它需要爲外部查詢的每個返回行執行一次,因爲它引用了外部查詢中的一個字段。

A JOIN爲整個結果集運行一次並得到合併。您的子查詢運行外部查詢,然後對於每個返回的行,它再次運行子查詢。

+1

我不認爲這是對的SQL Server。 – JeffO

+2

@Jeff - 那你錯了。 – JNK

1

最初的查詢會執行多次的子select,因爲行數很少,因此性能較差。

當你JOIN你得到整個結果集一次。