2012-06-26 50 views
1

可能重複:
Mysql: Perform of NOT EXISTS. Is it possible to improve permofance?與不加入表存在的查詢

有沒有做一個更好的/最佳方式。我應該使用exists而不是join?還是兩個單獨的查詢?那麼臨時表怎麼樣,因爲我正在閱讀有關這些表格的內容,但並不確定

從組獲取成員電子郵件。檢查他們還沒有收到物品。

SELECT m.email,g.id 
FROM group g 
    LEFT JOIN members m 
    ON g.mid = m.id 
    AND g.gid='1' 
WHERE NOT EXISTS 
     (SELECT id 
     FROM items AS i 
     WHERE i.mid=m.id 
     AND i.item_id='5' 
    ) 
+0

@Amit Bhargava - no as mine is three tables with a join。 – timeout

+0

如果你只想要來自一個組的成員,爲什麼你有'LEFT JOIN'? –

+0

@ypercube - 是的,這是正確的,但我也想從組中的身份證。 ty – timeout

回答

3

這裏寫成加入同一件事:

SELECT m.email, g.id 
From members m 
JOIN group g ON g.mid = m.id AND g.gid = '1' 
LEFT JOIN items i ON i.mid = m.id AND i.item_id = '5' 
WHERE i.id IS NULL 

使用下面的複合索引:

group (mid, gid) 
items (mid, item_id) 

我顛倒了左成員和組的加入,因爲它看起來像你'返回成員,而不是團體,並且我將LEFT JOIN更改爲INNER JOIN,因爲您只需要來自該組的成員。

我覺得這個可能會更好地閱讀:

SELECT m.email, g.id 
From members m 
JOIN group g ON g.mid = m.id 
LEFT JOIN items i ON i.mid = m.id AND i.item_id = 5 
WHERE g.gid = 1 
    AND i.id IS NULL 

你可能會想,如果我們也可以在i.item_id = 5部分移動到WHERE子句。你不能因爲沒有行i.id IS NULLi.item_id = 5。您必須首先執行連接,然後消除WHERE子句中的NULL行。

+0

是的,你是正確的加入應該是其他方式大聲笑。關於2個連接對1個連接存在的問題存在,這是表現明智的方式。我問,因爲這個查詢將運行在一個cron作業。 – timeout

+0

@timeout,NOT EXISTS [比JOIN慢](http://explainextended.com/2009/09/18/not-in-vs-not-exists-vs-left-join-is-null-mysql/) ,但最重要的部分是指標。 –

+0

有趣的閱讀,謝謝 – timeout

1

我不認爲臨時表是必要的。如果我們無法獲得可接受的表現,我們只會走這條路。

從您的查詢,我們收集您的模式是這樣的:

group (id INT PK, gid INT, mid INT) 
items (id INT PK, item_id INT, mid INT) 
members (id INT PK, email VARCHAR) 

它看起來像你的group表是一個真正的「會員」表,解決/實現之間的許多一對多的關係組和一個人。 (也就是說,一個人可以是零個,一個或多個組的成員;一個組可以有零個或多個人作爲成員。)

您在使用groupmembers之間的左連接。當沒有匹配的成員時,這將返回一個組(返回group.id)的行,members.email爲NULL(這可能是你想要的)。但是,如果您只想返回電子郵件地址,則可以將其更改爲INNER JOIN。

NOT EXISTS謂詞可以用OUTER JOIN和從JOINED表返回的NULL值的測試替換。如果group.gid和/或items.item_id列是數字數據類型,則可以從謂詞中的整數文字中刪除引號。

這裏是將返回的等效結果集的替代形式,可以更好地執行:

SELECT m.email 
    , g.id 
    FROM members m 
    JOIN group g ON g.mid = m.id AND g.gid = 1 
    LEFT 
    JOIN items i ON i.mid = m.id AND i.item_id = 5 
WHERE i.id IS NULL 

附錄:

TEST CASE(在選擇的回答評論提供)顯示在結果差在ON子句和WHERE子句中的謂詞items.item_id = 5之間設置。 (把這個謂詞移動到WHERE子句用反連接混淆。)

CREATE TABLE `group` (`id` INT PRIMARY KEY, `gid` INT, `mid` INT); 
CREATE TABLE `items` (`id` INT PRIMARY KEY, `item_id` INT, `mid` INT); 
CREATE TABLE `members` (`id` INT PRIMARY KEY, `email` VARCHAR(40)); 

INSERT INTO `group` VALUES (1,1,1), (2,1,2); 
INSERT INTO `items` VALUES (1,5,1); 
INSERT INTO `members` VALUES (1,'[email protected]'),(2,'[email protected]');