所以我在我的架构中有一个看起来像这样的表:
CREATE TABLE group_members(
group_id UUID NOT NULL,
account_name TEXT NOT NULL,
PRIMARY KEY (group_id, account_name)
);
假设我的帐户名称为peter
,我想选择某些群组中的所有其他成员(符合特定条件,我稍后会解释),其中我是其成员in。我想出了两个问题:
SELECT account_name,
group_id
FROM group_members
WHERE group_id IN
(
SELECT group_id
FROM group_members
WHERE account_name = 'peter'
INTERSECT
SELECT unnest('{"550e8400-e29b-11d4-a716-446655440000"}' :: uuid []))
AND group_members.account_name != 'peter';
和
WITH my_groups AS
(
SELECT account_name,
group_id
FROM group_members
WHERE account_name = 'peter'
INTERSECT
SELECT 'peter',
unnest( '{"550e8400-e29b-11d4-a716-446655440000"}' :: uuid []))
SELECT group_members.account_name,
group_members.group_id
FROM group_members,
my_groups
WHERE my_groups.group_id = group_members.group_id
EXCEPT
SELECT *
FROM my_groups;
INTERSECT子查询采用一组group id,并为peter所属的所有组过滤它。
我应该使用哪一个?或者有更简单的方法吗?因为,老实说,两个查询EXPLAIN看起来都很可怕。
答案 0 :(得分:2)
您应该测试数据的效果,并根据您的要求选择最佳数据。我的倾向是第一种方法,只需稍作改动:
SELECT account_name,
group_id
FROM group_members gm
WHERE EXISTS (SELECT 1
FROM group_members gm2
WHERE gm2.account_name = 'peter' AND
gm2.group_id = gm.group_id
) AND
gm.group_id IN (SELECT unnest('{"550e8400-e29b-11d4-a716-446655440000"}' :: uuid []) AND
gm.account_name <> 'peter';
此方法可以利用group_members(group_id, account_name)
上的索引。使用这样的索引,查询应该非常快 - 扫描外部查询的索引,然后使用子查询的索引获取匹配。
您的版本可能也会有非常好的表现;有时,UNION
和INTERSECT
等设置操作会影响使用索引的能力。