2009-07-24 62 views
15

作爲示例,我想要獲取應用了特定標籤的所有項目的列表。我可以做以下之一:SQL效率:在子查詢與加入的位置然後GROUP

SELECT Item.ID, Item.Name 
FROM Item 
WHERE Item.ID IN (
    SELECT ItemTag.ItemID 
    FROM ItemTag 
    WHERE ItemTag.TagID = 57 OR ItemTag.TagID = 55) 

或者

SELECT Item.ID, Item.Name 
FROM Item 
LEFT JOIN ItemTag ON ItemTag.ItemID = Item.ID 
WHERE ItemTag.TagID = 57 OR ItemTag.TagID = 55 
GROUP BY Item.ID, Item.Name 

或者完全不同的東西。

一般來說(假設有一條通用規則),什麼是更高效的方法?

+0

@Larsenal:您可以在第二個查詢中用`INNER JOIN`替換`LEFT JOIN`,結果將是相同的。一個`LEFT JOIN`將返回`ItemTag`中沒有相應的`Item.ID`的行的`NULL`,並且`WHERE`條件會將它們過濾掉。 – Quassnoi 2009-07-24 19:45:20

回答

15
SELECT Item.ID, Item.Name 
FROM Item 
WHERE Item.ID IN (
    SELECT ItemTag.ItemID 
    FROM ItemTag 
    WHERE ItemTag.TagID = 57 OR ItemTag.TagID = 55) 

SELECT Item.ID, Item.Name 
FROM Item 
LEFT JOIN ItemTag ON ItemTag.ItemID = Item.ID 
WHERE ItemTag.TagID = 57 OR ItemTag.TagID = 55 
GROUP BY Item.ID 

你的第二個查詢不會編譯,因爲它引用Item.Name沒有任何分組或聚合就可以了。

如果我們去掉GROUP BY從查詢:

SELECT Item.ID, Item.Name 
FROM Item 
JOIN ItemTag 
ON  ItemTag.ItemID = Item.ID 
WHERE ItemTag.TagID = 57 OR ItemTag.TagID = 55 

這些仍然是不同的查詢,除非ItemTag.ItemIdUNIQUE鍵和標註。

SQL Server能夠在UNIQUE列檢測IN狀態,只會改造IN條件爲JOIN

如果ItemTag.ItemID不是UNIQUE,則第一個查詢將使用一種SEMI JOIN算法,其在SQL Server中相當有效。

可以trasform第二查詢到JOIN

SELECT Item.ID, Item.Name 
FROM Item 
JOIN (
     SELECT DISTINCT ItemID 
     FROMT ItemTag 
     WHERE ItemTag.TagID = 57 OR ItemTag.TagID = 55 
     ) tags 
ON  tags.ItemID = Item.ID 

但是這一次是比INEXISTS效率較低的一件小事。

請參閱本文中我的博客更詳細的性能對比:

4

我認爲這取決於優化器如何處理它們,甚至可能會導致相同的性能。顯示執行計劃在這裏是你的朋友。

1

這幾乎是不可能的(除非你是那些瘋狂的數據庫管理員之一)告訴什麼是快速的,什麼不會不查看執行計劃和/或運行一些壓力測試。

+2

事實上,很容易說出來:第二種方式更快。它只會拒絕在納秒左右進行編譯。 – Quassnoi 2009-07-24 18:34:10

+0

我想我現在已經修好了。 – Larsenal 2009-07-24 19:02:57

2
SELECT Item.ID, Item.Name 
... 
GROUP BY Item.ID 

這不是有效的T-SQL。 Item.Name必須出現在group by子句中或集合函數(如SUM或MAX)中。

0

運行以下命令:

SET SHOWPLAN_ALL ON 

然後運行查詢的每個版本

,你可以看到,如果他們返回同樣的計劃,如果不看TotalSubtreeCost每個的第一行上,看看他們有多麼不同。

0

性能似乎總是拿到票,但你也聽到「這是買便宜的硬件比程序員「

第二次贏得表現。

有時候很高興看一下SQL並知道目的,但這就是註釋的意思。第一個查詢使用另一個表作爲過濾器 - 非常簡單。

第二個將更明智(從理解的目的,而不是性能)使用不同的代替group by。我希望有一些聚合在選擇,但沒有任何。速度殺死。

0

第二個在MySQL中更高效。 MySQL將在每個WHERE條件測試的IN語句中重新執行查詢。