如何加速大型数据库中rails的计分板计算

时间:2017-01-14 03:49:49

标签: ruby-on-rails postgresql

从大约100k行用户表和15000k行得分表数据库中,我可以通过哪些方式加快总分计算?我已经在score表中添加了user_id的索引。 现在,速度是: 呈现的用户/ _user_row.html.erb(3.0ms) 在布局/应用程序中呈现users / index.html.erb(1970.1ms) 在2113ms完成200 OK(浏览次数:343.8ms | ActiveRecord:1768.3ms)

我拥有的是

User_controller:

def index
 @users = User.by_total_points.limit(50)
end

User.rb型号:

has_many :points

def self.by_total_points
 joins(:points).group('users.id').order('SUM(points.value) DESC')
end

def total_points
 self.points.sum(:value)
end

point.rb模型:

belongs_to :user

Schema.rb

create_table "points", force: :cascade do |t|
t.integer  "user_id",    null: false
t.integer  "value",      null: false
t.string   "label",      null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end

add_index "points", ["user_id"], name: "index_points_on_user_id", using: :btree

create_table "users", force: :cascade do |t|
t.string   "first_name",            null: false
t.string   "last_name",             null: false
t.string   "username",   limit: 32, null: false
t.string   "email",                 null: false
t.datetime "created_at",            null: false
t.datetime "updated_at",            null: false
t.integer  "sumscore"
end

2 个答案:

答案 0 :(得分:0)

所以这不是一个Rails问题,更多的是系统设计问题。如果你只是想要获得前50名,你可以

  1. 使用priority queue并保留前50名玩家的一堆
  2. 缓存(在redis中,或者只是一个单独的表)。
  3. 每当你需要渲染得分板时,你只需要拉出50个玩家。
  4. 这样,你就可以在50条记录上插入nlog(n)的时间,它是渐近渐变的。

    在这个系统中,你将有两个scroing表,或一个表,一个redis数组。主表保留所有分数,缓存表或数组只保持前50名。

    如果您尝试获得所有排名,您可以将排序树(n-nary)和存储桶用户构建为得分范围,以便您执行log(n)插入和读取。设置有点复杂,我建议避免使用它,除非你每秒有数百个写入更新分数,而你的应用需要实时排名,而且你有超过1亿用户。

答案 1 :(得分:0)

很多答案都是关于它被击中的频率,点数更新的频率以及分数过时的可能性。

您最终可能会使用缓存或计数器。只是随意刺伤它而没有任何背景

  1. 在内存中设置缓存,并为每个用户提供总点数的缓存键
  2. 为前50名用户及其积分设置内存缓存
  3. 当有人更新积分时,会更新该用户的第一个缓存,如果他们现在位于前50位,也会更新缓存
  4. 现在,您可以检查缓存,而不是点击数据库,您的请求现在可以快速点亮,但需要花费额外的工作来更新缓存。

    http://guides.rubyonrails.org/caching_with_rails.html

    额外注意:在丢失缓存时,还要编写一个rake任务来重建这些任务。