zoukankan      html  css  js  c++  java
  • 关于论坛数据库的设计(分表分库等-转)

    关于论坛数据库的设计

    文章分类:数据库
    一个简单的论坛系统

    1:包括下列信息:

    2:每天论坛訪问量300万左右,更新帖子10万左右。

    请给出数据库表结构设计,并结合范式简要说明设计思路。

    一. 发帖主题和回复信息存放在一张表,并在这个表中添加user_name字段
    对数据库的操作而言,检索数据的性能基本不会对数据造成非常大的影响(精确查找的情况下),而对表与表之间的连接却会产生巨大的影响。 特别在有巨量数据的表之间。因此对问题的定位基本能够确定:在显示和检索数据时,尽量降低数据库的连接以及表与表之间的连接;
    引用
    1: user:用户基本信息表
    字段有:user_id,user_name,email,homepage,tel,add...

    2: forum_item:主题和回复混合表
    字段有:id,parent_id,user_id,user_name,title,content,....

    parent_id=0或者null表示是主题,否则=n表示是id=n那条帖子的回复
    UserName字段是冗余的,因此在用户改动UserName的时候就会产生同步数据的问题。这个须要程序来进行弥补

    二. 主题表和主题回复分开保存
    引用
    1: user:用户基本信息表
    字段有:user_id,user_name,email,homepage,tel,add...

    2: forum_topic:主题表
    字段有:id,user_id,title,content,....

    3: forum_topic_back:主题回复表
    字段有:id,topic_id,user_id,title,content,....

    三. 主题表的内容单独设计成一个表
    引用
    1: user:用户基本信息表
    字段有:user_id,user_name,email,homepage,tel,add...

    2: forum_topic:主题表
    字段有:id,user_id,title,....

    3: forum_topic_content:主题内容表
    字段有:id,topic_id,content

    4: forum_topic_back:主题回复表
    字段有:id,topic_id,user_id,title,content,....

    四.用户信息分2个表保存,并对相关表进行分表处理
    引用
    1: 简单用户表 tb_user:
    id , username

    2: 用户具体信息表 tb_userinfo
    id,userid , email , homepage , phone , address ...

    3: 论坛主题表 tb_bbs
    id , userid , title , ip , repleycount , replyuserid , createtime , lastreplytime

    4: 论坛内容标 tb_bbs_content (此表可依照bbsid进行分表存储)
    id,bbsid , content;

    5: 论坛回复表 tb_bbs_reply (此表可依照bbsid进行分表存储)
    id , bbsid , userid , content , replytime , ip

    五.添加一个主题缓存表,取每一个区的前面100条记录
    引用
    1: 简单用户表 tb_user:
    字段有:id , username

    2: 用户具体信息表 tb_userinfo
    字段有:id,userid , email , homepage , phone , address ...

    3: 论坛主题表 tb_bbs
    字段有:id , userid , title , ip , repleycount , replyuserid , createtime , lastreplytime

    4: 论坛内容标 tb_bbs_content (此表可依照bbsid进行分表存储)
    字段有:id,bbsid , content;

    5: 论坛回复表 tb_bbs_reply (此表可依照bbsid进行分表存储)
    字段有:id , bbsid , userid , content , replytime , ip

    6: 主题缓存表 tb_bbs_cache
    字段有:id , userid , title , ip , repleycount , replyuserid , createtime , lastreplytime

    ------------------------------------------------------------------------------
    以下是针对上面的方案展开的讨论:

    1:方案一表面上看起来好像少查了一张表,但由于冗余,由于帖子数量极大,会占用大量的空间。这样的数据量大,可是对实时和数据绝对安全性要求较低的应用。大量使用缓存的话能够极大提高处理能力。

    2:方案一你这么设计的话。索引怎么建比較好呢。还有就是会不会造成这个表过热。还有…… 我认为像论坛这种系统,使用缓存能够大大减少数据库的负载

    3:大家的意思是分成主题表、回复表等多个表? 还是合成一个表然后做物理分区? 哪种更好呢?

    4:再这么高插入更新的频率下 索引就有些不有用了,创建索引会减少插入更新的速度并且訪问量这么大的情况下。索引不建议採用

    5:就这种一个论坛,实时在更新、发帖、回帖。我认为在数据库上建立索引不太好,可是假设不建立索引怎样来提高查询等方面性能呢?

    6:都是分布式数据库了。放在多个表中,直接关联一点都没问题。重要是横向切分

    7:认同分表,分库,缓存的做法
    引用
    问题分析:
    每天论坛訪问量300万左右,更新帖子10万左右。
    1. 读写比例在30:1左右, 应向读取效率方面倾斜. 索引建立需參考经常使用读取的主keyword.
    2. 每月数据在10W*30=300W. 可按月分表
    3. 每年帖子在300W*12=3600W, 推算数据不会小于30T. 可按年分库

    结构:
    用户信息:独立表,userid主键
    发帖、回帖:按月表存储,帖子唯一ID主键,日期索引。
    帖子内容明细:按月存储,帖子唯一ID主键

    8:拿一张500万的表来说事
    引用
    更新的时候假设没有索引的话
    更新时间大概须要30秒左右 指的是全表更新~~
    而查询某单行记录 却须要10秒左右~~

    而增加索引的话
    更新时间几乎相同慢了一倍有余
    而查询记录则缩减到毫秒级~~
    快了百倍有余~~

    孰重孰轻 自己选

    9:自己的一点经验:
    引用
    1.分表存储;
    2.建立索引;SQL按所以查询的速度还是非常快的;
    3.避免整表扫描;先读取主题,在依照主题ID读取回复;再依照用户ID读取用户;而不要使用关联;
    4.使用缓存;

    10:须要分3张表,且建立索引。。。


    理由例如以下:
    引用
    1:建立3张表能够避免冗余数据。维护起来方便。。。
    2:每天论坛訪问量300万左右,可见基本的压力来自于查询。sql查询的效率在于避免全表扫描。可见建立索引是必须的。


    3:关于创建索引会减少插入更新的速度这个问题是不存在的。。。

    由于。索引之所以会减少更新的速度的速度,是由于在更新完相应字段后还须要更新相应字段的索引。


    4:看到更新帖子10万左右。这句话是说,我们可能对发帖标题。发帖内容,回复标题。回复内容这4个字段做更新。。。须要注意的是。这四个字段并非用来建立表连接的字段。为了优化查询速度我们不会在这四个字段上建立索引,所以从这道题目出发,我们建立的索引不会影响更新帖子的性能。

    。。

    所以,我觉得最后的答案是建立3张表,在连接用到的字段上建立索引。。。

    11:
    引用
    兩個表然後建一個視圖是否可行呢?

    视图也是非常慢的。

    12:每天就更新10万个帖子,每天訪问那么多,肯定是不能把全部的主贴放在一个表里,大表分小表,建立经常使用字段的索引。然后配置缓存。级联关系最好不要配置。等须要的时候再查询。

    13:尽管题目中没有说明,但实际应用中,查阅帖子通常仅仅会分页显示,而一页最多也就显示几十个帖子,那么实际上仅仅要SQL语句构造得好,T_USER表事实上仅仅是跟一个仅仅有几十行结果集的的子查询进行连接,应该基本不用操心出现性能问题。

    并且实际上。一个万行级的表简单关联百万行级的表(事实上镇魂歌数量级在我看来事实上也算不上非常大的表),在数据库方面全然有非常多优化方式,甚至能够通过提高硬件配置来改善性能,实在没有非常大必要进行结构上的冗余。一旦结构有冗余,为了保证数据一致性,往往你还要消耗很多其它的资源,反而得不偿失。

    14:分表有垂直和水平分表
    引用
    1:不管你拿多少记录(甚至是1条),假设两个大表关联都可能会产生很大的中间值,假设你排序(排序字段没实用到索引),你都可能导致数据库採用各种各样的方式来计算。

    2:索引会导致插入、更新记录非常慢,大家都是知道的。

    3:水平分表能够解决问题,仅仅要你能保证每一个表仅仅存适合的记录数(比如100W一个表) (水平分区也能够解决IO的一些问题)

    4:还有就读写分离,master是写,slave是读 (再加上cache,一般问题都还好了)

    上面都是比較大的工作量,最好是保证你的数据库设计是合理的(范式是第一步,然后考虑反范式),基本上也能满足非常多问题了。

    15:方案四 把内容与其他信息分开的优点就是能够让每一个表的文件最小化,对数据库操作压力会减小,操作速度会快,还能够搭配缓存,把内容依据情况进行缓存,能够尽量非常少訪问表数据。
    引用
    1:对于上述分表方式也能够适用于分库操作,这样就减少了数据库单库的压力,把压力分散到各个机器
    2:我的做法就是尽量避免表关联
    3:再就是对于sql语句尽量都保证索引有效,不能索引的sql,尽量採用能索引的高效方式解决

    16:外围的方案:
    引用
    1 读方面,生成静态页,或者缓存最新最热的帖子。


    2 写方面,预计主要是INSERT吧,这个能够异步操作的。全部的写贴操作放到一个队列然后批量运行插入数据库操作。

    17:方案四比較靠谱,再加上定期转储,海量的cache。大型论坛就此搞定。

    18:我认为应该还是使用3张表比較合适。
    引用
    1:业务上说,非常可能主贴跟回复贴拥有不同的扩展,比方附件什么的,都放在一张表里面,假如主贴跟回复存在个性需求,怎么办?无限加字段么?
    2:主贴跟回复在同一张表里,会增大锁表的几率。
    3:索引的确会减少表更新的速度,可是带来的查询效率提升也是非常可观的,因此我认为,索引不能不用,可是要少用。
    4:建立表时,确实能够通过楼上某位仁兄回复所言,用水平分表的方式,事实上原理就是用先算再查嘛。
    5:在前端表现上,能够使用ajax等方式,分步骤取数据,比方主贴的内容先取出来,然后再逐步载入回复信息等。

    19:提快速度的关键:
    引用
    1.建立索引并在查询时充分利用;
    2.避免使用关联,这样避免整表扫描;使用关联不如多次使用主键查询来的快;
    3.一些处理的功能尽可能放到内存中来做,比方组织主题和回复;
    4.使用静态页面也是个不错的做法;

    20:方案三是延续了hibernate二级缓存的思想, 对于常常更新的数据都设计成单独表。这样能够最大程度的利用hibernate缓存

    21:没有fast=true的设置,有人说or比in 好,exists比in 好,索引比全表扫描好,分区能提高查询效率,可是分区要减少插入效率
    我要说的是,没有fast=true的选项, 假设能找到一步,或者几步公式化的方法能提高效率,那么优化器自己就会做了,根本不用用户操心。
    如果 or比in好,数据库优化器把in语法和or语法走的运行计划一样就能够了,何必折磨用户呢。
    说点实际的,非常多人张嘴就说,SQL优化就是避免全表扫描,不知道大家有没有了解过索引查找的原理.索引查找数据,有两步要做,第一步是索引中高速查询,索引里仅仅存储了相应表数据的rowid, 所以还有第二步,依据rowid去得到所有的数据, 所以须要一次磁盘i/o, 不要小看磁盘I/O,通过索引查询出的结果比較多的时候,磁盘i/o的时间是非常大的,这个时候比全表扫描慢得多, 实际上,oracle 10g基于成本的优化器(CBO),选择性不高的索引,优化器根本不会使用,而自己主动採用全表扫描的方式来做.

    22:这个量级的bbs我设计过,当时是这样做的(方案五):
    引用
    共四个表:
    1. 用户表
    2. 主题表(包括最后回复信息,最后回复人,最后回复id等)
    3. 回复表
    4. 主题缓存表(这个取每一个区的前面100条记录),一般来说负载最大的就是主题的第一页,所以缓存表是个小表。

    共3台app集群,1台web,2台oracle一主一备,执行下来速度还是可接受的。

    23:不建议进行表的设计冗余。感觉就想反复代码一样。有坏味道
    引用
    1:缓存经常使用的页面和数据
    2:读写表或库分开(基于垂直分隔)
    3:数据库能够进行垂直分隔(字段分到多个表中)。再进行水平分隔(数据分到多个表中)
    4:论坛功能能够进行分隔,不同的server负责不同的功能,如图片server,webserver,邮件server等

    总之,就是要细化分工

    24:支持方案三的设计
    读取的操作:
    引用
    1:显示帖子列表界面,如果主贴内容放在forum_topic表,那么这就是冗余的,如果都要获取100个帖子,一行的数据长度越大,数据库须要扫描的数据块就越多,性能也越差。
    2:在打开一个帖子时,读操作通过索引关联到两张表(forum_topic和forum_topic_content)性能消耗对整个数据库来说不多。

    写帖子的操作:
    引用
    发表帖子,对标题表和内容表分别作一个插入

    更新非索引列不会引起索引更新:
    引用
    仅仅要被索引的列(比如回复表的标题ID)不被频繁更新,即使索引所在地行的其他列被频繁update,索引也不会被更新从而产生性能消耗,一张表一天30万次的索引更新,因它引起的性能消耗小到即使数据库安装在奔腾3单核CPU下都能轻松承担下来, 为什么会有人对索引有这么大的误解呢?。

    对一个论坛(或者绝大部分的系统)来说,检索(SELECT)数据耗费的系统资源远远高于更新数据(INSERT/UPDATE)本身,而索引是专门为检索数据服务的,难道就为了节省更新数据的小小的性能消耗,付出检索100条数据时须要数据库扫描几千万上亿条数据进行数据匹配的代价?假设是这种话,即使是有32核顶级CPU的数据库作并行查询都未必顶得住。

    做数据库设计,还是多了解数据库的原理才好。

    25:数据库切分是必须的。


    引用
    1:垂直切分:用户表、用户信息表、主题表、主题内容表、回复表
    2:水平切分:主题1、主题2、主题3、...、主题n
    3:缓存:缓存路由表
    4:再配合数据库读写分离和集群吧

    另:事实上论坛改动标题、内容的概率是非常小的。大部分都是新增

  • 相关阅读:
    10. Regular Expression Matching
    9. Palindrome Number (考虑负数的情况)
    8. String to Integer (整数的溢出)
    7. Reverse Integer (整数的溢出)
    LeetCode Minimum Size Subarray Sum
    LeetCode Course Schedule II
    Linux 文件缓存 (一)
    LeetCode Tries Prefix Tree
    Linux : lsof 命令
    LeetCode Binary Tree Right Side View
  • 原文地址:https://www.cnblogs.com/wzzkaifa/p/6726299.html
Copyright © 2011-2022 走看看