2011-12-21 28 views
5

WHERE條款有什麼更好?大表上的SQL WHERE - >先加入小表或將FK直接放在WHERE子句中?

我有一個大桌子,FK到一張小桌子。我可以直接在FK上搜索,或者我可以加入FK表並在連接表上設置WHERE限制。什麼更好/更好?

所以這個:

SELECT lt.* FROM LargeTable lt 
WHERE lt.SomeId in(12,55) 

或者這樣:

SELECT lt.* FROM LargeTable lt 
INNER JOIN SmallTable st ON lt.SomeId=st.ItemId 
WHERE st.Id in(12,55) 


Set statistics time on測試這一點,但我沒想到這個結果。誰能解釋這裏發生的事情?

第一次測試沒有加入:

(946 row(s) affected) 
SQL Server Execution Times: 
    CPU time = 1544 ms, elapsed time = 1580 ms. 

與二測加入

(946 row(s) affected) 
SQL Server Execution Times: 
    CPU time = 2636 ms, elapsed time = 366 ms. 

編輯:當我做SELECT Id代替SELECT *,然後在不先查詢加入具有較低的經過時間,並且執行計劃中的查詢開銷爲無連接的25%與連接的查詢的75%。

+2

是'lt.Id'索引? – RedFilter 2011-12-21 16:12:49

+2

您應該包含實際的執行計劃,然後並行運行兩個查詢...... SQL Server會告訴您哪一個更快,爲什麼更快。 – 2011-12-21 16:13:39

+0

+1爲實際執行計劃。無需猜測。 – 2011-12-21 16:21:54

回答

4

根據您的執行計劃,這兩個查詢基本上掃描整個大表的每個記錄......第二個查詢僅從小桌子發現一小部分的記錄在掃描大型表格之前,這就是爲什麼兩者的相對成本都是50%。

我建議考慮對largeTable.SomeId索引,然後用第一個查詢去:

SELECT lt.* FROM LargeTable lt 
WHERE lt.SomeId in(12,55) 

編輯:

因此,最大的問題是,爲什麼與加盟查詢有一個較短的持續時間比沒有連接的查詢長。

我認爲馬丁·史密斯給了這個問題的答案:

你的第二個得到並行計劃的第一個不

你會發現,你的第一個查詢了更短的CPU時間,但更長的時間。粗略地說,您的第一個查詢花費較少的精力來完成服務器,但您的第二個查詢使用了一個並行計劃,並且邀請了多個處理器來執行查詢,因此完成所需時間更少,但總體工作量更大。

+1

約定 - 如果你已經知道這個id,並且不需要這些信息(或者限制某些行),爲什麼join?當然,如果你只有一些id,因爲你早些時候把它們拉出來了(比如'SELECT id WHERE key = @ input'),你可能想要重構一下... – 2011-12-21 17:13:03

+0

@ X-Zero:是我的第一個想法,但後來我得到了意想不到的時間,所以我想知道什麼會更好/更快。我要添加一個索引並忘記加入,但我只是想知道爲什麼。 – 2011-12-21 17:29:23

+0

@ErikDekker - 這應該考慮更多的性能角度(可以意外地改變,因爲顯然'不相關'的原因);如果你加入一個表格,我希望它對於上下文很重要 - 出於某種原因 - 你試圖以某種方式限制(或相乘)結果,或者檢索一些數據。如果這些都不明顯,那麼可能會造成令人擔憂的錯覺,即錯過了某些東西。 – 2011-12-21 17:42:35

0

兩件事情要考慮:

  1. 沒有你的內部聯接返回一組較小的數據嗎?在這種情況下,您的where條件在較少的行上執行。
  2. 我想在你的第二個查詢您的意思是說其中st.Id(12,55),在這種情況下,你的where子句運行鍼對該集羣,因此很多快於主鍵索引你的非聚集外鍵索引
+0

1:都給我946行(見問題)。 2:是的,我的意思是,我修改了這個問題! (我的測試是好的壽) – 2011-12-21 16:26:48

+0

最終都給你946,但在你到達where子句之前,你的結果集縮小?如果你的lt.SomeId是可爲空的,這種情況會發生,在這種情況下,所有沒有lt.SomeId的記錄都不會被where子句評估。如果它不是空的,那麼唯一剩下的就是第二點(搜索主鍵比搜索外鍵要快,即使加入了加入的費用 – 2011-12-21 16:31:39

+0

但是他們alawys是否會給出相同的結果?是不是可能在table1中有一個id爲12的記錄,它不在table2中?這兩個查詢在功能上是不同的。在第二個查詢中,數據必須在第一個查詢中的兩個表中都存在,僅在一個表中。 – HLGEM 2011-12-21 17:30:26

0
  1. 由於兩個查詢都是從大表中提取結果,如上所述。那麼,您是否有「SomeID」列的Non clustered Index

  2. 您是否使用此表中的所有列。如果情況並非如此。建議僅提及所需的列。

  3. 同時作爲查詢從大表讀取數據,因此它可以從第一個查詢只能用「非聚集索引」做

  4. 如果有任何情況下只得到匹配的數據。那麼你可以像下面這樣做。

    Select ColumnName From 
    (
    Select ColumnName, SomeID from LargeTable Where SomeID in(12,13) 
    )T 
    Inner Join SmallTable T1 on T.SomeID = T1.SomeID 
    
  5. 如果你想非常快速的結果。你可以像下面這樣做。

    Create table #Large 
    (
        Id Int, 
        ColumnName Varchar(100) 
    ) 
    Insert into #Large(ID, ColumnNmae) 
    Select ColumnName, SomeID from LargeTable Where SomeID in(12,13) 
    

最後用加入

Select ColumnName From #Large T 
Inner Join SmallTable T1 on T.SomeID = T1.SomeID 

,並沒有加入

Select ColumnName from #Large