我网站上的用户为说唱歌词创建注释(示例).我想创建一个排行榜,以奖励创建最多注释的人.
排行榜应该跟踪每个用户整体创建的注释数量,以及他在过去一周,一天中创建的数量等.
我实现整个排行榜没有问题:
@users = User.all
Contributor | Annotations |
---|---|
<%= u %> | <%= u.annotations.size %> |
但是当我尝试实现(比如说)每日记分牌时,我正在重复代码并且操作非常缓慢(因为它必须遍历内存中的每个注释而不是依赖于数据库排序/计数):
Contributor | Annotations |
---|---|
<%= u %> | <%= u.annotations.select{|a| a.created_at > 1.day.ago }.size %> |
实施每日/每周记分牌的最佳方法是什么?
排行榜作为一个整体是一个痛苦的实施.那么,根据我的经验,实际的实施是相当直接的,只是它们难以扩展.通常,您发现自己必须运行许多数据库密集的数据库查询.要处理每日/每周报告,可能会查询日期时间列,但这意味着您在所述列上有索引.该索引实际上仅对排行榜查询有用,并且它使该表上的所有其他写入付出代价,因为必须重新计算索引.
另一种方法是按计划的间隔生成统计信息,并将该数据写入单独的表,排行榜查询使用该表.例如,你有一个后台工作,每天晚上你运行一个查询(也许它是一个昂贵的,因为它不使用日期时间索引,但由于它只运行一次,并通过后台作业,费用是"ok"),该查询依次写入到统计数据表中确实有日期时间列的索引,那么你重写你的排行榜页面打你预先计算的统计数据.根据您的需要,您可能会让cron脚本执行其他数据调整和预先计算,因此排行榜页面必须尽可能少地进行计算.
此时,您的排行榜页面正常工作,当它遇到带索引的表时,仍然需要读取大量行.这假设您拥有不错的流量.在每个页面上有一个索引查询命中大量行仍然很昂贵.所以现在考虑实现页面缓存,可能在memcached中存储数据.也就是说,由于每日排行榜数据每天最少变化,因此根据定义,在每个页面视图上重新运行这些数据库查询的成本很高.在memcached中缓存每日数据更有意义,每个页面视图只能访问memcached.
因此,您可以看到它的演变过程.如果您的流量低于您可能没有单独的表并且只在日期时间列上有索引的情况.运行总和,计数和平均值可能没问题.但它没有规模.因此,您必须考虑将其分解为更优化的结构.然后你会看到每天一遍又一遍地运行相同的查询而底层数据在24小时内没有变化是很昂贵的,所以你转到缓存设置.有许多活动部件,它可以变得复杂,好吧,真的很快很乏味.
当谈到排行榜时,我是一个充满战斗力的玩世不恭的人,虽然他们非常适合游戏机制和激励人们(每个人都喜欢看分数!)但这对于大规模开展工作很麻烦.