sql优化注意事项

SQL 最佳实践 - 不要将 count(*) 与 0 进行比较 自己的思考

看到这篇文章最大的感受就是在平常开发中,容易被一些所谓的开发经验所蒙蔽。正如我在看这篇文章之前,可能也不会在意,但是通过思考作者与自己的场景相近时反思自己也有这种情况。反向其他人也有这种情况。

作者:我时不时就会看到这样的东西:


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

作者:这让我有点痛苦。所以,我想,我要写写它的问题所在,以及如何避免这种结构。

让我们来看看某些人在写这篇文章时是怎么想的。此查询将返回地址为零的所有用户。换句话说,就是从未提供过任何地址的用户。

看来问题确实是发生在这里

这有什么不好呢?毕竟,如果我们需要查找没有地址的用户,它就能完成需要做的事情?没错。不对

这里似乎以为解决了问题,但是就是因为这个地方没有考虑到,大的数据量,性能问题,反思自己在之前的开发中确实也出现过这个问题,当时做的是一个活动排行榜的的功能。自己测试然后到了测试,没有测试高并发的情况导致,上线活动推广出现问题。

问题在于计算。如果一个用户有数百万个地址,会发生什么情况?Pg 会尽职尽责地统计所有地址,但随后会拒绝该行,因为其中有问题。

问题是,你并不需要一百万个地址。即使有两个地址,也需要对它们进行计数,虽然时间成本会低于百万行计数,但它仍然存在,而且是 100% 的无用功。

因此,问题可能是:如何正确地做这件事?很简单,有EXISTS表达式:

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

EXISTS(在本例中为 NOT EXISTS)会在找到一行后立即检查并放弃测试。无需计数。

当然,在某些(大多数?)情况下,当人们使用这种结构(0 == 计数)时,有人会说:”但在我们的情况下,这并不重要,因为……”。这就是标题中 “最佳实践”的由来。一个人不应该做错事,即使在这种特殊情况下它们并不重要,至少不要养成做错事的习惯,然后在真正重要的时候不小心犯了同样的错误。

这里其实有点误区要注意:
明知道,这样不好还是这样做了
不知道,这样不好这样做了

解决:
有意识的,那就不要养成做错事的习惯
无意识,做了有了反馈,不断的优化

参考
不要用 SQL 的 count(*) 语句与 0 比较(英文)