在我们的在线竞赛系统中,有一个经常变化standings
的整数列表格(user_id, score)
。两者都使用唯一约束进行索引。需要两种查询:
- 给定一个
score
不在表中的值,返回从 1 开始的位置,如果它被插入,分数将占据的位置。 - 给定
user_id
表中的a,返回对应分数的位置。
在这两种情况下,位置都是相对于分数升序的:比表中当前所有分数小的新分数将具有位置 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 解决,那么确认这一点是这个问题的下一个最佳结果。