计算来自多个表的连接数
Posted
技术标签:
【中文标题】计算来自多个表的连接数【英文标题】:Count Joins from Multiple Tables 【发布时间】:2020-09-28 01:02:57 【问题描述】:作为参考,我使用的是 Postgres 9.2.23。
我有几个表,其中一个表 (user_group
) 与其他一些表相关(例如:posts
、group_invites
和其他一些表)。还有一个 groups
表,但它不包含我在这些查询中需要的任何数据。
表user_group
:
fk_user_group_id, fk_user_id, fk_group_id, fk_invite_id user_status, ...
表message
:
pk_message_id, fk_user_id, fk_group_id, child_message_id, ...
表group_prospective_user
:
pk_prospective_user_id, fk_group_id, ...
我想获取指定组 ID 列表的每个相关表的一些统计信息如果用户是该组的成员。
现在我对每个相关表进行一次查询,例如:
select
"public"."user_group"."fk_group_id" as "groupId",
count(case
when (
"public"."message"."child_message_id" is null
and "public"."message"."pk_message_id" is not null
) then "public"."message"."pk_message_id"
end) as "numDiscussions",
count("public"."message"."pk_message_id") as "numDiscussionPosts"
from "public"."user_group"
left outer join "public"."message"
on "public"."message"."fk_group_id" = "public"."user_group"."fk_group_id"
where (
"public"."user_group"."fk_group_id" in (
1, 11, 23, 530, 1070
)
and "public"."user_group"."role" in (
'ADMINISTRATOR', 'MODERATOR', 'MEMBER'
)
and "public"."user_group"."fk_user_id" = 17517
)
group by "public"."user_group"."fk_group_id"
对于邀请:
select
"public"."user_group"."fk_group_id" as "groupId",
count(case
when "public"."prospective_user"."status" = 1 then "public"."prospective_user"."pk_prospective_user_id"
end) as "numInviteesExternal"
from "public"."user_group"
left outer join "public"."prospective_user"
on "public"."prospective_user"."fk_group_id" = "public"."user_group"."fk_group_id"
where (
"public"."user_group"."fk_group_id" in (
1, 11, 23, 530, 6176
)
and "public"."user_group"."role" in (
'ADMINISTRATOR', 'MODERATOR', 'MEMBER'
)
and "public"."user_group"."fk_user_id" = 17517
)
group by "public"."user_group"."fk_group_id"
统计组邀请数量的查询与上面的查询非常相似。只需更改 count when
和 join on
。
对这些表的每个查询都具有相同的相关逻辑,用于检查当前用户所属的组。有没有有效的方法将多个类似的查询合并到一个查询中?
我尝试将多个LEFT JOIN
s 与select count distinct
一起使用,但这在包含大量消息和大量邀请的群组中遇到了性能问题。有没有办法通过子查询轻松/有效地做到这一点?
【问题讨论】:
快速提示:使用表别名并避免重复长的多部分表名。 @Parfait 谢谢!我实际上正在使用 JOOQ,所以这一切都是为我自动生成的,但我会记住它以备将来使用。另外,我想如果我在这里这样做会有助于提高可读性,现在我想到了。 我认为这看起来像带有所有双引号和多部分标识符的 ORM。由于 SQL 答案可能比用 JOOQ 编写的更复杂,因此请考虑提出jooq
和 java
问题。
我的直接答案是通过组列将两者作为派生表连接起来。很难避免重复计算以合并来自不同数据源的汇总问题。
与您的问题无关,但是:Postgres 9.2 是no longer supported,您应该尽快计划升级。
【参考方案1】:
用户@Parfait 的答案是我能找到的最具扩展性的解决方案。我的查询基于本教程:https://www.sqlteam.com/articles/using-derived-tables-to-calculate-aggregate-values。
虽然这并不完美,并且会导致一堆子查询运行,但它确实可以一次获取所有数据,并且只需一次访问数据库。
结果是这样的:
"groups"."groupId",
coalesce(
"members"."member_count",
0
) as "numActiveMembers",
coalesce(
"members"."invitee_count",
0
) as "numInviteesInternal",
coalesce(
"discussions"."discussions_count",
0
) as "numDiscussions",
coalesce(
"discussions"."posts_count",
0
) as "numDiscussionPosts"
from (
select "public"."user_group"."fk_group_id" as "groupId"
from "public"."user_group"
where (
"public"."user_group"."fk_group_id" in (
1, 2, 3, 4, 5
)
and "public"."user_group"."role" = 'ADMINISTRATOR'
and "public"."user_group"."fk_user_id" = 123
)
group by "public"."user_group"."fk_group_id"
) as "groups"
left outer join (
select
"public"."user_group"."fk_group_id" as "members_group_id",
count(distinct case
when "public"."user_group"."role" in (
'ADMINISTRATOR', 'MODERATOR', 'MEMBER'
) then "public"."user_group"."pk_user_group_id"
end) as "member_count",
count(distinct case
when "public"."user_group"."role" = 'INVITEE' then "public"."user_group"."pk_user_group_id"
end) as "invitee_count"
from "public"."user_group"
group by "public"."user_group"."fk_group_id"
) as "members"
on "members_group_id" = "groupId"
left outer join (
select
"public"."message"."fk_group_id" as "discussions_group_id",
count(case
when (
"public"."message"."child_message_id" is null
and "public"."message"."pk_message_id" is not null
) then "public"."message"."pk_message_id"
end) as "discussions_count",
count("public"."message"."pk_message_id") as "posts_count"
from "public"."message"
group by "public"."message"."fk_group_id"
) as "discussions"
on "discussions_group_id" = "groupId"```
【讨论】:
以上是关于计算来自多个表的连接数的主要内容,如果未能解决你的问题,请参考以下文章