我正在构建一个论坛应用程序,用户可以在其中发布消息。这些消息可以被其他人看到。
表结构(简化):
// table: users
user_id | username | gender
---------------------------
1 | john | m
2 | jane | f
...
// table: posts
post_id | user_id | title
-------------------------
1 | 1 | Hello
...
// table: views
view_id | post_id | user_id | timestamp
---------------------------------------
1 | 1 | 2 | 2020-01-01 12:00:00
...
现在,我想创建一个查询以返回有关此帖子的一些统计信息。我想获得唯一的视图(每次用户查看一个帖子时,都会记录该日志,但是我只想对所有用户计数一次),并且想要获得男女比例。
SELECT
title,
(SELECT COUNT(DISTINCT user_id) FROM views WHERE post_id = 1) AS unique_views,
(SELECT COUNT(user_id) FROM users WHERE gender = 'm' AND user_id IN (SELECT user_id FROM views WHERE post_id = 1) AS male_views,
(SELECT COUNT(user_id) FROM users WHERE gender = 'f' AND user_id IN (SELECT user_id FROM views WHERE post_id = 1) AS female_views
FROM
posts
WHERE
post_id = 1
该查询有效,但这是一个包含5个子查询的查询。我尚无大量数据需要测试,但是当我说+ 1m用户,+ 1m帖子和+ 10m视图时,恐怕性能会下降。
一种不同的方法是将查询完全拆分为多个查询:一个用于全部唯一视图,另一种用于性别视图(具有唯一性),但是仍然总共是6个查询。
我正在使用PostgreSQL,并且在users.user_id
,users.gender
,posts.post_id
,views.view_id
,views.post_id
上有一个索引。
Question:还有另一种方法(例如,使用JOIN)来执行此查询,并且当数据库容量增加时会具有更好的性能吗?
您可以加入并执行条件聚合,而不是嵌套子查询:
select
p.title,
count(distinct u.user_id) unique_views,
count(u.user_id) filter(where u.gender = 'm') male_views,
count(u.user_id) filter(where u.gender = 'f') female_views
from views v
inner join users u on u.user_id = v.user_id
inner join posts p on p.post_id = v.post_id
where p.post_id = 1
group by p.post_id, p.title