我正在尝试拥有一个类似排行榜的平台,该平台在后端使用 ruby on rails。我正在使用 postgres 数据库。我的用户表有许多列类似于此排行榜的统计信息。我的目标是确定用户是否存在于任何列的前 100 名中,并返回这些列。这是我目前完成任务的代码,尽管很差
def check_user(user)
User.column_names.filter do |name|
User.all.order("#{name} DESC").limit(100).index(user)
end
end
虽然这有效并给出了正确的结果,但问题是每个查询都是单独执行的。在我当前的设置中,我需要检查大约 4500 列,导致对数据库进行 4500 多次查询。有什么方法可以在不进行每次检查和单独的数据库查询的情况下完成此任务?或任何其他整体加速过程的方法
我当前的架构看起来像这样。
create_table "users" do |t|
end
create_table "weapon_stats" do |t|
t.belongs_to :user
t.integer :weapon_kills_ak47
t.integer :weapon_shots_ak47
t.integer :weapon_uses_ak47
t.integer :weapon_hits_ak47
...
end
create_table "player_stats" do |t|
t.belongs_to :user
t.integer :character_used_a
t.integer :character_used_b
t.integer :character_used_c
...
end
create_table "misc_stats" do |t|
t.belongs_to :user
t.integer :mission_completed_a
t.integer :mission_completed_b
t.integer :mission_completed_c
...
end
所有列都是整数,范围从 0 到 32 位有符号整数限制,大约有 4500 个单独的统计数据需要跟踪。该数据库大约有 250,000 个用户,我预计不会超过 1M-2M。
在这个特定案例之外,我需要能够显示每个单独统计数据的前 100 名。每个用户还需要在没有太多开销的情况下轻松更新。
如果需要更多信息,所有代码都在这里https://github.com/0lafe/payday2Charts
这不一定是答案,但评论太长了。
我会考虑将应用程序重新设计为
class User < ApplicationRecord
has_many :user_stats
end
# name (e.g. player, weapon, mission)
class StatCategory < ApplicationRecord
has_many :stats
end
# name, stat_category_id
class Stat < ApplicationRecord
belongs_to :stat_category
end
# user_id, stat_id, stat_value
class UserStat < ApplicationRecord
belongs_to :user
belongs_to :stat
end
这简化了结构,同时使其易于扩展。
此外,它通过以下方式简化了查询或缓存“排行榜”:
SELECT
ranked_stats.user_id,
ranked_stats.stat_id,
ranked_stats.stat_value,
ranked_stats.position
FROM
(
SELECT
user_stats.*,
ROW_NUMBER () OVER(PARTITION BY stat_id ORDER BY stat_value DESC) As position
FROM
user_stats
) As ranked_stats
WHERE
ranked_stats.position <= 100
注意: 这些只是建议,尚未在您的生产环境中或以任何方式进行大规模审查