【发布时间】:2012-07-22 08:40:41
【问题描述】:
在我们的在线竞赛系统中,有一个经常变化的表格standings,其中整数列(user_id, score)。两者都使用唯一约束进行索引。需要两种查询:
- 如果
score不在表中,则返回从 1 开始的位置,如果插入该分数将占据该位置。 - 给定表格中的
user_id,返回对应分数的位置。
在这两种情况下,位置都是相对于分数升序的:比表中当前所有分数小的新分数将具有位置 1。
这是困难的部分:我们可能负担不起表扫描。该表可能有多达 1000 万条记录,我们需要每秒处理至少 40 个查询。
如何在 PostgreSQL 中做到这一点?
我在 Berkeley DB 中有一个非 SQL 解决方案,它使用支持逻辑记录号的 B 树。它很容易具有足够好的性能。但是我们想通过使用 PostgreSQL 查询重新实现来摆脱 BDB。我已经尝试了明显的
select 1+count(*) from standings where score < ? limit 1;
这会导致表扫描。
我希望答案是“不可能”,因为 BDB 的逻辑记录编号功能需要为每次编辑锁定整个 B 树。为了获得 O(log N) 的性能,它依赖于每个节点中的叶子数。 root 路径中的所有这些计数都必须随着每次编辑而改变;因此,锁定。这种锁定违反了 PostgreSQL 的设计原则,并且可能违反了任何多用户数据库。
因此,如果问题不能用 PostgreSQL 解决,那么确认这一点是这个问题的下一个最佳结果。
【问题讨论】:
-
该表是只读的吗?还是只在特定时间/很少写?如果是,你能负担得起添加一列
position吗? -
不,随着人们添加参赛作品,它会经常变化。
标签: sql postgresql ordinal