2009-02-12 10 views
1
類別

選擇記錄我有工作,並且運行速度不夠快上我的表(50K上的產品+,3K +類別< 0.01秒)的SELECT語句。但在我看來,它不是很優雅,並希望聽到任何改善它的建議。SQL:屬於例外的類別,只有屬於排除

有感興趣的3個表:

  • 產品 - 關鍵的productID
  • 類別 - 關鍵的categoryID
  • products_tree - 鏈接表(類別包含許多產品,產品可以屬於多個類別)

我已經排除categoryIDs列表[例如1040,1050,1168] 我要選擇屬於這些排除的類別之一的所有productIDs 只有當產品不屬於其他非排除類別

我的查詢看起來是這樣的:

SELECT DISTINCT productID 
FROM products_tree 
WHERE 
    categoryID IN (1040,1050,1168) 
    AND productID NOT IN 
    (SELECT DISTINCT productID 
     FROM products_tree 
     WHERE 
     categoryID NOT IN (1040,1050,1168) 
    ); 

回答

1

我能想到的幾個方法,每個方法根據索引和特定的數據庫實現執行不同的操作。有些可能看起來很慢的可以通過您可能沒有想象到的方式進行優化,因此值得試用它們並比較執行計劃以瞭解發生了什麼...

注意1:我使用GROUP BY而不是DISTINCT,這是因爲它允許優化器使用索引。我見過的實施工作了,他們可以把DISTINCT到一個GROUP BY,但它在拳頭地方使用GROUP BY可以肯定的是非常值得的。它也讓你思考索引,這絕不是壞事。

注2:一些像這樣的查詢需要一段時間進行優化,因爲有很多選擇的優化器來評估。因此,通常值得編譯所有的不同選項中存儲過程和比較這些存儲過程的執行。這確保您的比較實際上是查詢時間而不是不同的編譯時間。

SELECT 
    [tree].productID 
FROM 
    products_tree AS [tree] 
WHERE 
    [tree].productID IN (1040,1050,1168) 
    AND NOT EXISTS (SELECT * FROM products_tree WHERE productID = [tree].productID AND categoryID NOT IN (1040,1050,1168)) 
GROUP BY 
    [tree].productID 


SELECT 
    [tree].productID 
FROM 
    products_tree AS [tree] 
LEFT OUTER JOIN 
    (
     SELECT 
     productID 
     FROM 
     product_tree 
     WHERE 
     productID NOT IN (1040,1050,1168) 
     GROUP BY 
     productID 
    ) 
    AS [ok_products] 
     ON [ok_products].productID = [tree].productID 
WHERE 
    [tree].productID IN (1040,1050,1168) 
    AND [ok_products].productID IS NULL 
GROUP BY 
    [tree].productID 


SELECT 
    [tree].productID 
FROM 
    products_tree AS [tree] 
GROUP BY 
    [tree].productID 
HAVING 
     MAX(CASE WHEN [tree].productID  IN (1040,1050,1168) THEN 1 ELSE 0 END) = 1 
    AND MAX(CASE WHEN [tree].productID NOT IN (1040,1050,1168) THEN 1 ELSE 0 END) = 0 

還有其他的,每個的變化,但是這應該給你一個很好的開始。但我真的要強調使用GROUP BY和考慮指標:)

+0

產品ID和類別ID都在各自的表中的主,而且INDEX在鏈接表上。 我將DISTINCT更改爲GROUP BY,並獲得了完全相同的性能。我想優化器注意到了這一點。 您在學術上有趣的SQL建議,所以我接受了這個答案。 – rwired 2009-02-13 02:31:00

0

我相信你的查詢是相當不錯的,但加入,你可以比較一下:如果

 
SELECT DISTINCT pt1.productID 
FROM products_tree pt1 
LEFT JOIN products_tree pt2 ON pt2.productID = pt1.productID 
    AND pt2.categoryID pt1.categoryID 

WHERE pt1.categoryID IN (1040,1050,1168) 
    AND pt2.productID IS NULL 

不知道我想正確的,但我想你理解我的做法。不過,我會選擇productinfo直接,如果你想要的,那麼聯接會更有意義(內加入您需要的類別,左連接你不想讓那些和檢查null)

0

你可以嘗試「NOT EXISTS」變種:

SELECT 
    pt.productID 
FROM 
    products_tree pt 
WHERE 
    pt.categoryID IN (1040,1050,1168) 
    AND NOT EXISTS (
    SELECT 1 
    FROM products_tree 
    WHERE productID = pt.productID AND categoryID NOT IN (1040,1050,1168) 
) 
GROUP BY 
    pt.productID; 
相關問題