SQL best practices – don’t compare count(*) with 0

每次看到这样的SQL都会让我抓狂:

SELECT u.* FROM users u
WHERE 0 = (SELECT COUNT(*) FROM addresses a WHERE a.user_id = u.id);

一起来分析一下这样写有什么问题,如何避免这种写法。

写这样的SQL,明显是为了搜索出没有填写地址的用户列表。

这么写不对吗?我们是找没有地址的用户,看起来也没有什么问题,问题在于计数!!!

如果有个用户关联了上百万的地址,系统就要全查出来,并统计出数量!!!

实际上哪怕没有上百万的地址记录,如果有2个、3个,这种计数的性能损耗也是非常多余的。

所以,什么样的SQL才适用于这种情况呢?答案就是 EXISTS

SELECT u.* FROM users u
WHERE NOT EXISTS (SELECT FROM addresses a WHERE a.user_id = u.id);

EXISTS (示例中是 NOT EXISTS) 会高效率检查是否至少有一条地址纪录,而不用计数。

当然,总有人说我这么写也没有错吧啦吧啦,是的,所以标题是最佳实践,建议大家养成好的SQL或编程习惯,只有这样才能避免极端情况下的错误。

引用

转自 depesz@depesz.com 的blog,近期刚好用到,特此记录。