2

可能重复:
Mysql:执行不存在。是否可以提高性能?

有没有更好/最佳的方法来做到这一点。我应该使用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'
      ) 
4

2 回答 2

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 子句。你不能因为没有行 wherei.id IS NULLi.item_id = 5. 您必须先执行连接,然后消除 WHERE 子句中的 NULL 行。

于 2012-06-26T16:20:53.420 回答
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您在和之间使用 LEFT JOIN members。当没有匹配的成员时,这将为组返回一行(返回 group.id),members.email 为 NULL(这可能是您想要的)。但如果您只想返回电子邮件地址,则可以将其更改为 INNER JOIN。

NOT EXISTS 谓词可以替换为 OUTER JOIN 和从 JOINED 表返回的 NULL 值的测试。如果group.gidand/oritems.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

附录:

测试用例(在对选定答案的评论中提供)演示了在子句中使用谓词和在子句中的查询之间结果集items.item_id = 5ON差异WHERE。(将此谓词移动到 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,'one@m.com'),(2,'two@m.com'); 
于 2012-06-26T17:50:33.597 回答