sum()与count()

rya*_*hee 11 sql postgresql aggregate-functions

考虑在PostgreSQL中实现的投票系统,其中每个用户可以在"foo"上向上或向下投票.有一种foo存储所有的"富信息"表和votes存储表user_id,foo_idvote,其中vote是+1或-1.

要获得每个foo的投票结果,以下查询将起作用:

SELECT sum(vote) FROM votes WHERE foo.foo_id = votes.foo_id;
Run Code Online (Sandbox Code Playgroud)

但是,以下内容也可以正常工作:

(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))
Run Code Online (Sandbox Code Playgroud)

我目前有一个索引votes.foo_id.

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

编辑

很多答案都考虑到了votenull 的情况.我忘了提到NOT NULL投票栏有一个限制.

此外,许多人指出,第一个更容易阅读.是的,这绝对是真的,如果一位同事写了第二篇,我会愤怒地爆发,除非有表演的必要性.从来没有,问题仍然在于两者的表现.(从技术上来说,如果第一个查询方式比较慢,它不会是这种罪行写入第二个查询.)

Erw*_*ter 12

当然,第一个例子更快,更简单,更容易阅读.甚至在被水生生物拍打之前应该是显而易见的.虽然sum()稍微贵一些count(),但重要的是,第二个例子需要两次扫描.

但是,有一个实际的差别,也:sum()可以回到NULL这里count()没有.我引用了关于聚合函数手册:

应该注意,除了count之外,这些函数在没有选择行时返回空值.特别是,没有行的总和返回null,而不是像人们预期的那样为零,

由于您似乎在性能优化方面存在弱点,因此这里有一个您可能会喜欢的细节:count(*)比稍快一些count(vote).只有投票才有效NOT NULL.测试性能EXPLAIN ANALYZE.

仔细检查

这两个查询都是语法上的废话,独自站立.只有从SELECT更大的查询列表中复制它们才有意义:

SELECT *, (SELECT sum(vote) FROM votes WHERE votes.foo_id = foo.foo_id)
FROM   foo;
Run Code Online (Sandbox Code Playgroud)

这里重要的一点是相关子查询 - 如果你只是查询查询的一小部分,这可能没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;
Run Code Online (Sandbox Code Playgroud)

通常类似的表现.细节:

但是,在从表格中读取大部分或全部内容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);
Run Code Online (Sandbox Code Playgroud)

首先在子查询中聚合值,然后加入到结果中.
关于USING: