V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
njutree
V2EX  ›  程序员

一个关系数据库设计问题,想请教大家有没有更好的解决方案。

  •  3
     
  •   njutree · 2014-11-12 17:47:42 +08:00 · 3407 次点击
    这是一个创建于 3662 天前的主题,其中的信息可能已经有所发展或是发生改变。
    描述如下:
    有一张用户的表,一张新闻的表,现在的需求是向用户推送没有读过的新闻。ps.新闻和用户的数量都非常庞大100w级以上。
    如果新开一张表来记录用户的已读未读状态则这个表的状态空间会非常庞大
    目前想到最好的方案就是只记录用户已经读过的新闻(即使这样如果新闻过期很慢,用户使用的时间越久这个表越大)。
    20 条回复    2014-11-14 13:16:44 +08:00
    morvencao
        1
    morvencao  
       2014-11-12 17:51:59 +08:00   ❤️ 1
    只记录用户用户已经读过的新闻来过滤是一种解决办法。
    求更有解决方案!
    cdxem713
        2
    cdxem713  
       2014-11-12 23:02:41 +08:00 via iPhone
    @morvencao 那最终纪录用户已读信息的表会有1,000,000*1,000,000条数据,肯定是不太合适吧
    我也期待一个好的设计
    scylla
        3
    scylla  
       2014-11-12 23:13:59 +08:00
    分表或者表分区可以么?
    morvencao
        4
    morvencao  
       2014-11-12 23:26:07 +08:00
    @cdxem713 是的,也许加个索引会稍微好点儿,但肯定不是最优解。
    JoeShu
        5
    JoeShu  
       2014-11-12 23:26:08 +08:00   ❤️ 1
    只记录读过新闻的用户,这个可以过滤掉一部分用户,用户量级能够降到10w以下,另外考虑到每个用户实际使用过程中并不会把所有100w新闻都读过,最多到1000条,可以把所有已读新闻放到一个字段里。
    实际上这种应用场景,不应该把数据放到数据库里,最好能够放到redis之类的内存中,可以设置过期时间,定期地备份迁移,而且能够提高查询速度。
    morvencao
        6
    morvencao  
       2014-11-12 23:31:20 +08:00
    @scylla 表的数据还是会随着时间沉积,所以这不是一个一蹴而就的办法。
    dddew
        7
    dddew  
       2014-11-13 00:11:09 +08:00
    只记录用户读过的新闻,并且每个月生成一张新表
    cdxem713
        8
    cdxem713  
       2014-11-13 08:23:08 +08:00 via iPhone
    @morvencao 主要还是单表数据量太大,冗余也高,建索引不会解决实际问题
    njutree
        9
    njutree  
    OP
       2014-11-13 09:53:50 +08:00
    @JoeShu 感谢放内存里面不失为一种提高速度的办法,在100w*1000的情况下大约消耗10G以上,不知道有没有什么分布式内存解决方案?
    njutree
        10
    njutree  
    OP
       2014-11-13 09:55:33 +08:00
    @dddew 按月分表应该不能解决问题吧?
    semicircle21
        11
    semicircle21  
       2014-11-13 11:56:03 +08:00
    "向用户推送没有读过的新闻" 有没有想过 该向用户推荐哪条新闻的思路?
    因为, 如果所有内容都是顺序推荐的, 比如从最新的新闻 id 12345 向 0 去推荐, 用户读了 5 条, 你就记一个id 12340 就可以了, 如果要新闻实时性 , 你可以考虑每小时新建表, 这个小时推荐完了就推荐上一个小时的, 每个进来读过的用户, 在每个小时的表里就一个 id 就可标记用户"读到哪了"
    icylogic
        12
    icylogic  
       2014-11-13 12:38:39 +08:00 via Android
    我觉得
    icylogic
        13
    icylogic  
       2014-11-13 12:45:29 +08:00 via Android
    额,这种东西在客户端维护一个栈式结构比较好?因为新闻的读过这种关系没有太大必要在服务器维护一个以后基本用不着的表,最多把栈中还剩下的id同步到服务器做个备份。。。如果是喜欢,关注这些关系那是需要永久记录,该开表就开。。。
    ryd994
        14
    ryd994  
       2014-11-13 13:21:32 +08:00
    把旧的定期分出去,毕竟旧的大概是不会有人看了
    ioth
        15
    ioth  
       2014-11-13 14:50:08 +08:00
    按月份日期分表,做存贮过程。
    njutree
        16
    njutree  
    OP
       2014-11-13 16:23:37 +08:00
    @semicircle21 这里举的新闻只是个列子,实际推送的情况会比较复杂,推送的顺序和时间基本没有关系,你可以假设推送给用户的新闻是随机推送的,而且对不同的用户推送过程完全独立。
    semicircle21
        17
    semicircle21  
       2014-11-14 01:44:28 +08:00   ❤️ 1
    @njutree 如果真是限制在传统的关系型数据库, 那还有一种投机取巧的办法, 就是最多记录用户曾经读过的 N 条新闻, 用触发器超出条件时删一部分, 然后期待用户不会记得那么久以前看过的新闻, 或者新闻过了那么久就已经过期了.
    其实上面提到用 Redis 是不错的方案, 你提到的 10G 内存, 随便哪个靠谱的IaaS, 创建个 32G 48G 的内存的机器都很容易. 如果真要分片, 用 Redis cluster, 或者第三方的 twemproxy, 或者前两天就在这里见到的豌豆公司新开源的...专门去搜了下, 叫: wandoulabs / codis, 各种方案选择还是挺多的.
    semicircle21
        18
    semicircle21  
       2014-11-14 01:51:56 +08:00
    @njutree 还有一些"使用关系型数据库"但是超越传统关系模型的思路, 比如每个字段不止存一个 id, 而是存一个排好序的 list, 用 string 类型. 或者用个 blob, 用一些 kv 数据库的方案作为内容...这些方案都有走火入魔的味道---"既然如此, 干嘛用关系型数据库? 干嘛不直接用别的数据库?"
    njutree
        19
    njutree  
    OP
       2014-11-14 11:48:45 +08:00
    @semicircle21 非关系数据库了解的不多,曾经想过用位图法来标记每篇文章的已读未读状态但问题也是非常多
    semicircle21
        20
    semicircle21  
       2014-11-14 13:16:44 +08:00
    @njutree 其实无论是关系型数据库, 还是现在各式 NoSQL 数据库, 都有各自能解决问题的局限, 都没有编程语言数据结构的范畴, 这篇对开拓思路有帮助, 推荐一下: http://www.yinwang.org/blog-cn/2014/04/24/sql-nosql/
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3364 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 04:59 · PVG 12:59 · LAX 20:59 · JFK 23:59
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.