优化多对多连接

时间:2017-01-24 15:49:27

标签: sql postgresql

我有三个表:groupspeople以及groups_people,它们构成了groupspeople之间的多对多关系。

架构:

CREATE TABLE groups (
    id          SERIAL PRIMARY KEY,
    name        TEXT
);

CREATE TABLE people (
    id          SERIAL PRIMARY KEY,
    name        TEXT,
    join_date   TIMESTAMP
);

CREATE TABLE groups_people (
    group_id    INT REFERENCES groups(id),
    person_id   INT REFERENCES people(id)
);

当我想查询最近10个重新加入id = 1的组的人时:

WITH person_ids AS (SELECT person_id FROM groups_people WHERE group_id = 1)
SELECT * FROM people WHERE id = ANY(SELECT person_id FROM person_ids)
ORDER BY join_date DESC LIMIT 10;

查询需要扫描所有已加入的人,然后在选择之前对其进行排序。如果该组包含太多人,那将会很慢。 无论如何要解决它吗?

3 个答案:

答案 0 :(得分:3)

架构(重新)设计允许同一个人加入多个群组

您提到groupspeople之间的关系 是多对多的,我想你可能想把join_date移到groups_people (来自people),因为同一个人可以加入不同的组,每个组 此类事件有自己的join_date

所以我会将架构更改为

CREATE TABLE people (
    id          SERIAL PRIMARY KEY,
    name        TEXT --,                    -- change
    -- join_date   TIMESTAMP                -- delete
);                                      

CREATE TABLE groups_people (
    group_id    INT REFERENCES groups(id),
    person_id   INT REFERENCES people(id),  -- change
    join_date   TIMESTAMP                   -- add
);

<强>查询

select
    p.id
    , p.name
    , gp.join_date
from
    people          as p
    , groups_people as gp
where
    p.id = gp.person_id 
    and gp.group_id=1 
order by gp.join_date desc
limit 10 

免责声明:上述查询采用MySQL语法(问题最初标有MySQL

答案 1 :(得分:2)

使用joinorder by编写一个简单的limit似乎更容易:

select p.*
from people p join
     groups_people gp
     on p.id = gp.person_id
where gp.group_id = 1
order by gp.join_date desc
limit 10;   -- or fetch first 10 rows only

答案 2 :(得分:1)

尝试使用EXISTS

重写
SELECT *
FROM   people p
WHERE  EXISTS (SELECT 1
               FROM   groups_people ps
               WHERE  p.id = ps.person_id and group_id = 1)
ORDER  BY join_date DESC 
LIMIT 10;