可能重复:
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 :(得分:4)
这是与JOIN相同的东西:
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,因为看起来你正在返回成员,而不是组,并且我将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 NULL
和i.item_id = 5
的行。您必须先进行连接,然后消除WHERE子句中的NULL行。
答案 1 :(得分: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
表实际上是一个“成员资格”表,它解决/实现了一个组与一个人之间的多对多关系。 (也就是说,一个人可以是零个,一个或多个组的成员;一个组可以有零个或多个人作为成员。)
您在group
和members
之间使用LEFT JOIN。当没有匹配的成员时,这将为group返回一行(返回group.id),member.email为NULL(这可能是你想要的)。但是,如果您只想返回电子邮件地址,则可以将其更改为INNER JOIN。
可以使用OUTER JOIN替换NOT EXISTS谓词,并测试从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(在对所选答案的评论中提供)演示了在items.item_id = 5
子句和ON
子句中具有谓词{{1}}的查询之间的结果集的差异。 (将此谓词移动到WHERE子句会使用反连接。)
WHERE