sql - sum() 与 count()

标签 sql postgresql aggregate-functions

考虑一个在 PostgreSQL 中实现的投票系统,其中每个用户都可以对“foo”投票赞成或反对。有一个foo表存储所有的“foo信息”,还有一个votes表存储user_idfoo_idvote,其中 vote 为 +1 或 -1。

要获得每个 foo 的投票计数,可以使用以下查询:

SELECT sum(vote) FROM votes WHERE foo.foo_id = votes.foo_id;

但是,下面的方法同样有效:

(SELECT count(vote) FROM votes 
 WHERE foo.foo_id = votes.foo_id 
 AND votes.vote = 1)
- (SELECT count(vote) FROM votes 
   WHERE foo.foo_id = votes.foo_id 
   AND votes.vote = (-1))

我目前在 votes.foo_id 上有一个索引。

哪种方法更有效? (换句话说,哪个会跑得更快?) 我对特定于 PostgreSQL 的答案和一般的 SQL 答案都感兴趣。

编辑

很多答案都考虑到了 vote 为 null 的情况。我忘了提到投票列上有一个 NOT NULL 约束。

此外,许多人指出第一个更容易阅读。是的,这绝对是真的,如果一位同事写了第二个,除非有性能需要,否则我会气得发狂。尽管如此,问题仍然在于两者的表现。 (从技术上讲,如果第一个查询方式慢,那么编写第二个查询就不算犯罪。)

最佳答案

当然,第一个示例更快、更简单且更易于阅读。甚至在得到 slapped with aquatic creatures 之前就应该很明显了.虽然 sum()count() 稍微贵一点,但更重要的是第二个示例需要两次扫描。

但也有一个实际差异:sum() 可以返回 NULL,其中 count()没有。我引用 manual on aggregate functions :

It should be noted that except for count, these functions return a null value when no rows are selected. In particular, sum of no rows returns null, not zero as one might expect,

由于您似乎在性能优化方面存在弱点,这里有一个您可能会喜欢的细节:count(*) is slightly faster than count(vote )。仅当 vote 为 NOT NULL 时等效。使用 EXPLAIN ANALYZE 测试性能.

仔细观察

两个查询都是语法废话,单独存在。只有从更大查询的 SELECT 列表中复制它们才有意义,例如:

SELECT *, (SELECT sum(vote) FROM votes WHERE votes.foo_id = foo.foo_id)
FROM   foo;

这里的重点是相关子查询 - 如果您在查询中只读取一小部分 votes,这可能没问题。我们会看到额外的 WHERE 条件,您应该有匹配的索引。

在 Postgres 9.3 或更高版本中,替代的、更清晰的、100% 等效的解决方案是使用 LEFT JOIN LATERAL ... ON true:

SELECT *
FROM   foo f
LEFT   JOIN LATERAL (
   SELECT sum(vote) FROM votes WHERE foo_id = f.foo_id
   ) v ON true;

通常性能相似。详情:

但是,在从表 votes 中读取大部分或全部时,这会(快)得多:

SELECT f.*, v.score
FROM   foo f
JOIN   (
   SELECT foo_id, sum(vote) AS score
   FROM   votes
   GROUP  BY 1
   ) v USING (foo_id);

首先聚合子查询中的值,然后连接到结果。
关于使用:

关于sql - sum() 与 count(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14998225/

相关文章:

SQL 一个值属于集合

sql - 计算最大并发用户 session 数

c - libpq - PQsendQuery 等待完整结果

postgresql - 哪个(近)实时空间数据库可存储超过 100 万个条目?

sql - 用于计算风速(矢量大小)和风向(矢量方向)矢量平均值的Postgres聚合函数

mysql - 天数累计

sql - postgresql 空数组

java - 如何将子记录的插入限制为N条记录?

postgresql - 是否有任何方法可以在 Windows 64 位上的 Postgresql 9.3 64 位或 32 位中成功安装 PLPython?

python - 如何在pig或hive中使用array_agg()聚合函数