有2张桌子:
challenge
entry
(每个挑战有很多条目)
要输入挑战,需要输入他们的电子邮件和姓名(用于排行榜) - 没有注册/身份验证过程,因此email
和leaderboard_name
都记录在entry
表格中的每个条目中:
CREATE TABLE public.entry
(
id bigint NOT NULL DEFAULT nextval('entry_id_seq'::regclass),
challenge_id bigint NOT NULL,
date_created timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
email text COLLATE pg_catalog."default" NOT NULL,
is_removed boolean NOT NULL DEFAULT false,
total_points integer NOT NULL DEFAULT 0,
CONSTRAINT entry_pkey PRIMARY KEY (id)
)
使用这种方法,可以在一次质询中多次使用相同的电子邮件值。换句话说,可以创建具有相同电子邮件的多个条目。
现在,获取得分最高的不同电子邮件的查询非常简单:
SELECT DISTINCT ON (email)
id as entry_id, total_points
FROM entry
WHERE challenge_id = 1
AND is_removed = false
AND total_points > 0
ORDER BY email, total_points DESC, date_created;
在这里,我们不希望出现以下条目:
- a) 被管理员删除 (
is_removed = false
) - b) 得分为零 (
total_points > 0
)
这challenge_id = 1
也是必不可少的,因为它通过其 ID 将条目限制为特定挑战。
date_created
此外,如果有许多具有相同分数的电子邮件,则order by会为每封电子邮件选择最早的条目。这可确保每封电子邮件选择的条目始终相同。
当我尝试构建查询计划程序将使用的索引时,就会出现问题。
我尝试在以下位置创建索引:
- 3列:
email, total_points DESC, date_created
- 5列:
challenge_id, is_removed, email, total_points DESC, date_created
但EXPLAIN
不断返回entry
表的 Seq Scan。
奖金问题 - 如何有效地只选择前 N 个条目total_points DESC, date_created ASC
?最简单的方法是用另一个查询包装这个查询,但有没有更好的方法?