SQL / PostgreSQL:选择除self以外的所有成员

时间:2016-01-30 16:30:34

标签: sql postgresql

所以我在我的架构中有一个看起来像这样的表:

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看起来都很可怕。

1 个答案:

答案 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)上的索引。使用这样的索引,查询应该非常快 - 扫描外部查询的索引,然后使用子查询的索引获取匹配。

您的版本可能也会有非常好的表现;有时,UNIONINTERSECT等设置操作会影响使用索引的能力。