我有一个包含相当数量记录的数据库,我想找到没有存储用户项目的用户:
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
答案 0 :(得分:5)
例如 -
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将报告误报。