10000个学生,根据快速的根据考分来计算每个学生的击败率?

10000个学生,根据快速的根据考分来计算每个学生的击败率?
举个例子,10000个学生来考试,考完后提交得分,需要根据得分来计算学生的击败率(比如,我打败了90%的同学),每个学生提交答案的试卷不确定,有快,有慢。

我的疑问:每个学生提交答案后,所有学生的击败率都要重新计算,内存溢出了。

我现在的计算方式:按分数desc排序,循环每个学生,计算得分比这个学生多的人有多少。

我是一次取10000条记录呢,还是每次取100条数据,多循环几次?

阅读 6.9k
10 个回答

按你的描述,如果有以十亿个人,那你十亿个人都要重新算啊?这个时候肯定要换技术实现方式,使用 redis 的有序集合就可以轻松达到你的目标。简单说一下。

  1. 存储学生成绩到成绩表中:以学生唯一 id 为键,分数为值,将数据存储到 redis 有序集合中,假设成绩表
    redis 键名为:student_score_table,插入语法:ZADD 成绩表键名 学生分数 学生id,例如:ZADD student_score_table 66 1

  2. 获取成绩表中学生总数$countZCARD student_score_table

  3. 获取当前学生的成绩排名$rankZRANK student_score_table 学生id

  4. 计算得到该学生的击败率$beat_rate(保留两位小数)$beat_rate = round((1 - $rank / $count), 2) . '%';

  5. 获取排名前十的学生ZRANGE student_score_table 1 10

  6. 获取成绩在80到100之间即优秀学生ZRANGE student_score_table 80 90 WITHSCORES

参考

楼主这问题提的有点怪。击败率,无非就是分数比自己低的人,两条sql语句,一条交卷人数count,一条分数比自己低的人数count,两条sql语句不至于内存溢出吧!
像楼主那个样操作,每个人一提交,就更新之前所有提交的人的击败率,不内存溢出才有鬼。
如果楼主把这个击败率当成实时更新的字段。那只能用计划任务定时更新。
感觉没必要。一般来说数据列表都会分页,遍历的时候20条左右,就统计一次总人数,然后这20 count比他分数低的,花费不了多少时间。至于后期如果要数据导出,怕影响效率,写个脚本,直接把击败率一次性更新不就好了。

记录这次试题,规定一定时间内完成,其他情况视为0分处理,等时间到了,把所有提交的数据全那出来,自己排列计算,然后再赋值结果

0x1. 等所有学生都完成提交再做计算,最后得分根据交卷时间与成绩排名

你应该不是实时的把,即便是实时的你也可以做个`loding`,等确定所有人交卷完成再请求服务端进行排名和击败率把

0x2. 交卷应该有个统一等时间,比如答卷时间为120分钟

我觉得楼主最主要等是没搞明白产品逻辑把 ,您的那个循环是搞什么...

学生提交卷子的时候计算这个人的击败率即可。
已经提交完卷子的人再计算击败率没有意义。所以你这个处理好就行,不用计算全部人

楼主的击败率是要保存到表里吗?要是要保存到表里的话还是等都完成了之后再存比较好吧。
如果只是交卷的时候展示的话完全就不用太担心了吧?

没有必要实时计算所有人的击败率,
只需要在学生提交或者提交之后再次查询时计算这一个学生的击败率即可,
分数字段加个索引,每次计算一下分数比他低的人有多少,
提交的总人数做一个计数器就可以,每提交一个+1,计算击败率直接拿过来用就行了,效率很高,
最多就是10000个人同时请求而已,这是并发需求,服务器处理就可以了

数据表中只记录学生、分数

create table stu(
    stuid int,
    score FLOAT
)

另外建个视图

select stuid,(select count(1) from stu t2 where t2.score < t1.score)/(select count(*) from stu t3)*100 as beatRate
from stu t1

图片描述

做个分组比较好,比如1-20分一组,20-40分一组.....
这样统计每个组下的人数就好。

redis sorted set

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题