3

我有一个包含大量记录的数据库,我想找到没有存储用户项目的用户:

select `name`
  from `users`
 where `ID` not in (select distinct `userID` from `userItem`)

这个查询甚至不会在被 MySQL 服务器切断之前完成执行。这里有一些我不知道的巨大效率低下吗?

中有 200,000 条记录userItem和 14,000 条记录users

查询解释的结果:

1   PRIMARY users   ALL NULL    NULL    NULL    NULL    13369   Using where
2   DEPENDENT SUBQUERY  userItem    index   NULL    userID  8   NULL    189861  Using where; Using index; Using temporary
4

4 回答 4

5
  1. userItem.userID 和 user.ID 是否被索引?如果没有,请添加它们。
  2. 在 MySQL JOIN 子句中可能会更快。

例如 -

SELECT name
  FROM users u
  LEFT JOIN userItem ui
    ON ui.userID = u.ID
  WHERE ui.userID IS NULL
于 2012-10-04T13:51:54.043 回答
2

你的问题是“为什么”它这么慢。原因是 MySQL 为每一行重新执行子查询。你会认为它会执行一次子查询,然后就完成了。但是不,它会重新执行无数次。

我相信最快的替代方法是对@Parado 稍作改动:

select `name`
  from `users` u
 where not exists (select 1 from userItem ui where ui.userID = u.id limit 1)

您应该将它与 ui.UserId 上的索引结合使用。

于 2012-10-04T14:00:16.063 回答
0

也许not exists会更快:

select `name`
  from `users` u
 where not exists
 (select 1 
  from `userItem` ui 
  where ui.userID=u.id)
于 2012-10-04T13:47:40.503 回答
0

为用户(ID)和用户项目创建唯一索引(用户ID)。

Ex . SELECT DISTINCT a, b, c FROM t1 WHERE NOT EXISTS (SELECT NULL FROM t2 WHERE t1.a = t2.a AND t1.b = t2.b AND t1.c = t2.c)

即使您只检查一个键,使用 NOT IN 也不是最好的方法。原因是,如果您使用 NOT EXISTS,则 DBMS 只需在所需列存在索引的情况下检查索引,而对于 NOT IN,它将必须读取实际数据并创建随后需要检查的完整结果集.

使用 LEFT JOIN 然后检查 NULL 也是一个坏主意,当表很大时它会非常慢,因为查询需要进行整个连接,完全读取两个表,然后丢弃很多。此外,如果列允许 NULL 值,则检查 NULL 将报告误报。

于 2012-10-04T13:54:09.403 回答