我有三个表:groups
和people
以及groups_people
,它们构成了groups
和people
之间的多对多关系。
架构:
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;
查询需要扫描所有已加入的人,然后在选择之前对其进行排序。如果该组包含太多人,那将会很慢。 无论如何要解决它吗?
答案 0 :(得分:3)
架构(重新)设计允许同一个人加入多个群组
您提到groups
和people
之间的关系
是多对多的,我想你可能想把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)
使用join
和order 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;