>  Q&A  >  본문

MySQL包含需要“随时间变化值”的排序字段的数据库设计

使用数据库MySQL(innodb)
相关表设计最大数据量:5000w

假定表news,拥有以下字段:

id int auto_increment,
title varchar(2000) not null default '' comment '标题',
score int not null default 0 comment '基础分值',
visited int not null default 0 comment '展示次数',
voted int not null default 0 comment '投票数',
//hot int not null default 0 comment '热度', 不再作为独立字段,而是在select的时候来计算
created int not null default 0 comment '创建Unix时间戳',
primary key(id),
key score(score),
key visted(visited),
key voted(voted),
key created(created)

其中,hot字段的值是结合visited、voted计算并随着时间衰减的,衰减频率最短为1小时(即间隔1小时就需要根据当前时间戳与created的差值做一次衰减)。数据主要根据hot字段的值来排序展示的,因此需要保证整表hot数据的更新。

另外,我还需要记录一个hot的历史最高值。(补充)hot值有最大限制,不能超过100。

难点:如果独立一个hot字段,数据量大了之后,衰减更新的效率将非常之低并影响系统整体性能;如果另外设一个完全不包含衰减的分数值字段score,需要展示的时候实时再实时计算hot的值又怕SQL执行效率太低。

目前后者的效率肯定更高,不知道各位大神有没有做过类似的需求,有没有更好的方案,求解!


确定在visit和vote操作时更新递增的score值,然后在SELECT列表的时候实时计算经过时间衰减的hot值,对于提取的数据先通过where条件缩小范围,结果进行一定时间的cache缓存。感谢大家!

PHPzPHPz2766일 전622

모든 응답(4)나는 대답할 것이다

  • 巴扎黑

    巴扎黑2017-04-17 11:18:23

    这种设计有点让人迷惑,我在想为啥要设计衰减这个操作啊,如果时间因子是T的话,完全可以设计类似的公式啊

    hot = f(visited) * f(voted) * T
    

    越新的内容T肯定越大,所以即使他们的visitedvoted相同,它的hot值也会大些,如果你不希望时间因子的扰动有这么大的话也可以

    hot = f(visited) * f(voted) + f(T)
    

    这样hot值只需要一次计算就行了,不需要实时更新,因为你已经把时间因子设计到它里面了

    회신하다
    0
  • 怪我咯

    怪我咯2017-04-17 11:18:23

    我会展示的时候再实时计算hot的值,这样不受一小时的粒度限制,排序可以更实时地变化。

    如果效率太低,我就把最终考虑所有因素后生成的结果缓存起来。

    另:有种暗暗的感觉,题主一定是深受《基于用户投票的排名算法》系列文章毒害颇深。

    회신하다
    0
  • 黄舟

    黄舟2017-04-17 11:18:23

    很奇怪的做法,这个hot就不应该和原始数据放到一起,笨一点就用一个专用slave表每小时sql排序一次,彻底一点就单写一个模块去随时更新每个条目的hot值,存到另外一个地方供读取用。

    회신하다
    0
  • 大家讲道理

    大家讲道理2017-04-17 11:18:23

    不好意思,想咨询一下,您这个排名方式最终的实现方式,本人最近也受到类似问题困扰,感谢您的指导。。。谢谢。。

    회신하다
    0
  • 취소회신하다