PostgreSQL中的分组方式和计数
查询:PostgreSQL中的分组方式和计数,sql,postgresql,count,distinct,aggregate-functions,Sql,Postgresql,Count,Distinct,Aggregate Functions,查询: SELECT COUNT(*) as count_all, posts.id as post_id FROM posts INNER JOIN votes ON votes.post_id = posts.id GROUP BY posts.id; 返回Postgresql中的n记录: count_all | post_id -----------+--------- 1 | 6 3 | 4 3 | 5
SELECT COUNT(*) as count_all,
posts.id as post_id
FROM posts
INNER JOIN votes ON votes.post_id = posts.id
GROUP BY posts.id;
返回Postgresql中的n
记录:
count_all | post_id
-----------+---------
1 | 6
3 | 4
3 | 5
3 | 1
1 | 9
1 | 10
(6 rows)
我只想检索返回的记录数:6
我使用子查询来实现我想要的,但这似乎不是最佳的:
SELECT COUNT(*) FROM (
SELECT COUNT(*) as count_all, posts.id as post_id
FROM posts
INNER JOIN votes ON votes.post_id = posts.id
GROUP BY posts.id
) as x;
在PostgreSQL中,如何正确获取此上下文中的记录数?我认为您只需要从投票中获得
计数(不同的post\u id)
请参见中的“4.2.7.聚合表达式”一节
编辑:根据欧文的评论纠正了我粗心的错误。还有:
在Postgres中,如果n端有多个条目,通常比:
投票中每个帖子的行数越多,性能差异就越大。测试
<代码>计数(不同PASSIDID)必须读取所有行,对它们进行排序或散列,然后只考虑第一个相同的集合。code>EXISTS
将只扫描投票
(或者最好扫描post\u id
)上的索引,直到找到第一个匹配项
如果投票
中的每个post\u id
都保证出现在表posts
中(引用完整性强制使用外键约束),则此缩写形式相当于较长形式:
SELECT count(DISTINCT post_id) AS post_ct
FROM votes;
实际上可能比每个帖子没有条目或条目很少的EXISTS
查询更快
您的查询也以更简单的形式工作:
SELECT count(*) AS post_ct
FROM (
SELECT FROM posts
JOIN votes ON votes.post_id = posts.id
GROUP BY posts.id
) sub;
基准
为了验证我的声明,我使用有限的资源在测试服务器上运行了一个基准测试。都在一个单独的模式中:
测试设置
模拟典型的投票后/投票情况:
CREATE SCHEMA y;
SET search_path = y;
CREATE TABLE posts (
id int PRIMARY KEY
, post text
);
INSERT INTO posts
SELECT g, repeat(chr(g%100 + 32), (random()* 500)::int) -- random text
FROM generate_series(1,10000) g;
DELETE FROM posts WHERE random() > 0.9; -- create ~ 10 % dead tuples
CREATE TABLE votes (
vote_id serial PRIMARY KEY
, post_id int REFERENCES posts(id)
, up_down bool
);
INSERT INTO votes (post_id, up_down)
SELECT g.*
FROM (
SELECT ((random()* 21)^3)::int + 1111 AS post_id -- uneven distribution
, random()::int::bool AS up_down
FROM generate_series(1,70000)
) g
JOIN posts p ON p.id = g.post_id;
以下所有查询都返回了相同的结果(9107篇帖子中有8093篇有投票权)。我对
EXPLAIN ANALYZE
ant进行了4次测试,在postgres9.1.4的三次查询中,每一次都取了五次中最好的一次,并附加了结果总运行时间
ANALYZE posts;
ANALYZE votes;
CREATE INDEX foo on votes(post_id);
VACUUM FULL ANALYZE posts;
CLUSTER votes using foo;
CREATE INDEX foo on votes(post_id);
VACUUM FULL ANALYZE posts;
CLUSTER votes using foo;
count(*)。。。存在的位置
计数(不同的x)
-带连接的长格式
计数(不同的x)
-不带连接的缩写形式
- 353毫秒
- 348毫秒
- 366毫秒
存在时的结果
Postgres 9.5的相关、更详细的基准测试(实际上检索不同的行,而不仅仅是计数):
使用OVER()
和限制1
:
SELECT COUNT(1) OVER()
FROM posts
INNER JOIN votes ON votes.post_id = posts.id
GROUP BY posts.id
LIMIT 1;
为什么您认为它不是最佳的?这似乎是一种非常常见的操作,有一种更简单的方法。PG::Error:Error:column“posts.id”必须出现在GROUP BY子句中或在聚合中使用function@skinkelynet:这是因为答案有细微的错误-它必须是来自投票的。我在答案中添加了正确的表单。@LostCrotchet事实证明,您可以在PostgreSQL中这样做。你需要把字段列表放在括号里,例如…选择COUNT(DISTINCT(firstname,lastname))FROM people
。你说的“更便携”是什么意思?@a_horse_和_no_name:“更便携”真的是胡说八道。删除了那个位,谢谢你指出。我错误地认为SQLite不支持聚合函数中的DISTINCT
就像所有其他主要的RDBMS一样。作为补偿(因为我想为自己澄清这一点),我用一个基准阐述了性能角度。如果我读得正确,你就错过了我的CTE版本。不过,它应该相当于一个子查询。@wildplasser:很抱歉,重新创建了场景(不完全相同,但从安装程序中可以看到非常接近),并为CTE版本添加了结果。正如预期的那样,CTE在这里对性能没有帮助。
SELECT COUNT(1) OVER()
FROM posts
INNER JOIN votes ON votes.post_id = posts.id
GROUP BY posts.id
LIMIT 1;