我已经阅读了很多关于这个主题的帖子,比如 mysql-get-rank-from-leaderboards.
但是,没有一种解决方案能够从数据库中获得一系列排名.
问题很简单.假设我们有一个带有"id"列的Postgres表和另一个值不是唯一的INTEGER列,但我们有一个该列的索引.
例如,桌子可能是:
CREATE TABLE my_game_users (id serial PRIMARY KEY, rating INTEGER NOT NULL);
目标
尝试#1:row_number()窗口函数
WITH my_ranks AS 
  (SELECT my_game_users.*, row_number() OVER (ORDER BY rating DESC) AS rank
   FROM my_game_users)
SELECT *
FROM my_ranks
WHERE rank >= 4000 AND rank <= 4050
ORDER BY rank ASC;
这"工作",但在快速笔记本电脑上,查询平均550毫秒,100,000个用户,而没有任何其他实际工作.
我尝试添加索引,并重新措辞此查询以不使用"WITH"语法,没有任何方法可以加快速度.
尝试#2 - 计算具有更高评级值的行数 我尝试了这样的查询:
SELECT  t1.*,
  (SELECT  COUNT(*)
   FROM my_game_users t2
   WHERE (t1.rating, -t1.id) <= (t2.rating, -t2.id)
  ) AS rank
FROM my_game_users t1
WHERE id = 2000;
这是不错的,这个查询需要大约120毫秒,100,000个用户具有随机评级.但是,这仅返回具有特定id(2000)的用户的等级.
我看不到任何有效的方法来扩展此查询以获得一系列排名.任何扩展此尝试的尝试都会导致查询速度变慢.
我只知道"中心"用户的ID,因为在我们知道哪些用户在该范围内之前,用户必须按等级排序!
尝试#3:内存中有序树
我最终使用Java TreeSet来存储排名.每当新用户插入数据库或用户的评级发生变化时,我都可以更新TreeSet.
这是超快的,大约25毫秒,有100,000个用户.
但是,它有一个严重的缺点,它只在为请求提供服务的Webapp节点上更新.我正在使用Heroku并将为我的应用部署多个节点.所以,我需要为服务器添加一个计划任务,每小时重建一次这个排名树,以确保节点不会太不同步!
如果有人知道在Postgres中使用完整解决方案做到这一点的有效方法,那么我全都耳朵!
小智 0
如果您按降序排序,则您的顺序是正确的。使用 rownumber() 函数。 在 postgres 中选择行号
您还可以使用内存缓存将内容存储在内存中。像redis之类的东西。它是一个独立的应用程序,可以为多个实例提供服务,甚至可以远程服务。
| 归档时间: | 
 | 
| 查看次数: | 1575 次 | 
| 最近记录: |