为什么这个带有NOT IN语句的MySQL查询这么慢?

时间:2012-10-04 13:44:21

标签: mysql sql query-optimization

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

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

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

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

查询解释的结果:

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 个答案:

答案 0 :(得分:5)

  1. userItem.userID和user.ID是否已编入索引?如果不是,请添加它们。
  2. 在MySQL中JOIN子句可能更快。
  3. 例如 -

    SELECT name
      FROM users u
      LEFT JOIN userItem ui
        ON ui.userID = u.ID
      WHERE ui.userID IS NULL
    

答案 1 :(得分: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上的索引结合使用。

答案 2 :(得分:0)

也许not exists会更快:

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

答案 3 :(得分:0)

为(userid)创建用户(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将报告误报。