锁定老帖子 主题:从一道面试题想到的论坛数据库设计
精华帖 (7) :: 良好帖 (6) :: 新手帖 (10) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-04-28
我正在研究这个问题,期待大家讨论
|
|
返回顶楼 | |
发表时间:2009-05-05
按照楼主的数据量估算T_Topics 100-1000万之间,T_Reverts 1000万-1亿之间
我觉得可以这样去分析(不一定正确,但可以提供一种思路): 论坛和一般的应用有一个最大的区别,都是先列出所有主题(标题和部分内容),在用户选择之后再列出具体内容和回复,而且很多访问者都是从很多主题中选出感兴趣的再看。这样的话,可以做这么一个假设来分析,用户进来后打开第一个主题: 在topic和revert分表的情况下,整个操作可以被看做 1次100-1000万的遍历 + 1次100-1000万的精确查询 + 1次1000万-1亿的遍历。 如果合成一个表,则变成1次1000万-1亿的遍历 + 1次1000万-1亿的精确查询 + 1次1000万-1亿遍历。 两种方式相比较,2次百万级的查询被提升成2次千万级的,带来的性能损耗应该会超过2个表之间的连接带来的损耗吧。何况还有很多情况是用户进来看了几页主题列表才发现需要点开的,这时候合表带来的都是无谓损耗了。 |
|
返回顶楼 | |
发表时间:2009-05-06
思路都不对!
散列才是王道! 大数据量拆分成小数据量才能在根本上提升性能。 4个表结构。而非表 user topics topicsID_revertsID reverts topics的id对reverts做分表。 通过topicsID_reversID定义对于topics的id到那个reverts表找自己的reverts 比如定义topics的id在1-100w之间到reverts_1找它的reverts,100W+1-200w到 reverts_2找它的reverts,对于某个topics的reverts的操作都对同一个表。 当然topicsID_revertsID也可以通过配置文件完成。这没几条记录。加载到内存之。 |
|
返回顶楼 | |
发表时间:2009-06-05
经过讨论,怎么设计表不重要,关键是需要缓存。楼上的设计相当好一些。
|
|
返回顶楼 | |
发表时间:2009-06-12
缓存常用的页面和数据
读写表或库分开 数据库可以进行垂直分隔,再进行水平分隔 论坛功能可以进行分隔,不同的服务器负责不同的功能 不建议进行表的设计冗余,感觉就想重复代码一样,有坏味道 总之,就是要细化分工 |
|
返回顶楼 | |
发表时间:2009-06-12
两个表的设计是不适合的。我觉得应该是这样
1.用户信息表,储存用户的信息 2.标题表,包含标题ID(PK),提交用户ID(FK),提交时间,主题,回复数等,不含内容 3.内容表,包含内容ID(PK),标题ID(FK),提交用户ID,提交时间戳,标题,回复内容ID(FK SELF REF),是否主贴等. 读取的操作: 用户在打开论坛主页时,只需要看的是标题和用户名(关联标题表和用户表,1对1的关系),如果主贴内容放在标题表,那么这就是冗余的,假设都要获取100个主题,一行的数据长度越大,数据库需要扫描的数据块就越多,性能也越差。 在打开一个帖子时,需要看的主要是内容,需要关联二张表,关系是 N(内容表)对1(用户信息表)的关系。 两个读操作,每个操作关联到两张表。通过索引,不管是浏览帖子列表或者帖子内容,需要读的数据的性能消耗对整个数据库来说不多。 写帖子的操作: 1,发表帖子,对标题表和内容表分别作一个插入 2,回复帖子,对内容表做一次插入,对标题做一次更新(更新回复数等) 每天更新10万条帖子,这对数据库不构成什么压力 论坛系统的数据库操作基本上是insert,用到update的极少 关于缓存。我不清楚Hibernate缓存的原理是什么,在一组频繁更新的数据列表中,它如何维护它的缓存与数据库间的数据一致性,它如何检测出数据库的变更,然后自动更新缓存,特别是不使用二级缓存的情况下。个人理解,缓存只应缓存小容量数据(例如键值,标题列表等)而不存储大容量内容(例如帖子内容) 关于索引。只要被索引的列(例如回复表的标题ID)不被频繁更新,即使索引所在地行的其它列被频繁update,索引也不会被更新从而产生性能消耗,一张表一天30万次的索引更新,因它引起的性能消耗小到即使数据库安装在奔腾3单核CPU下都能轻松承担下来, 为什么会有人对索引有这么大的误解呢?。对一个论坛(或者绝大部分的系统)来说,检索(SELECT)数据耗费的系统资源远远高于更新数据(INSERT/UPDATE)本身,而索引是专门为检索数据服务的,难道就为了节省更新数据的小小的性能消耗,付出检索100条数据时需要数据库扫描几千万上亿条数据进行数据匹配的代价?如果是这样的话,即使是有32核顶级CPU的数据库作并行查询都未必顶得住。 做数据库设计,还是多了解数据库的原理才好。 |
|
返回顶楼 | |
发表时间:2009-06-17
leero 写道 rickqin 写道 leero 写道 由于访问对更新是300:10,访问占了30/31,为什么不把同一帖子的主贴和回复放一条记录里呢,
这位兄台的想法最帅!给个解释呢? 这样读取速度很快,读取一条记录肯定比读取多个记录快, 这样做带来的烦恼:更新帖子时候比较麻烦, 我觉得在一种情况下leero你的这个提议可行,就是: 用户发帖和回帖之后,不需要查看自己发了多少贴回了多少贴。 但是: 要是一个用户想查看自己发了多少贴,回了多少贴,那你该怎么做呢? 还有,你能预计一个主题贴有多少回帖吗? |
|
返回顶楼 | |
发表时间:2009-06-17
hyee 写道 两个表的设计是不适合的。我觉得应该是这样
1.用户信息表,储存用户的信息 2.标题表,包含标题ID(PK),提交用户ID(FK),提交时间,主题,回复数等,不含内容 3.内容表,包含内容ID(PK),标题ID(FK),提交用户ID,提交时间戳,标题,回复内容ID(FK SELF REF),是否主贴等. 读取的操作: 用户在打开论坛主页时,只需要看的是标题和用户名(关联标题表和用户表,1对1的关系),如果主贴内容放在标题表,那么这就是冗余的,假设都要获取100个主题,一行的数据长度越大,数据库需要扫描的数据块就越多,性能也越差。 在打开一个帖子时,需要看的主要是内容,需要关联二张表,关系是 N(内容表)对1(用户信息表)的关系。 两个读操作,每个操作关联到两张表。通过索引,不管是浏览帖子列表或者帖子内容,需要读的数据的性能消耗对整个数据库来说不多。 写帖子的操作: 1,发表帖子,对标题表和内容表分别作一个插入 2,回复帖子,对内容表做一次插入,对标题做一次更新(更新回复数等) 每天更新10万条帖子,这对数据库不构成什么压力 论坛系统的数据库操作基本上是insert,用到update的极少 关于缓存。我不清楚Hibernate缓存的原理是什么,在一组频繁更新的数据列表中,它如何维护它的缓存与数据库间的数据一致性,它如何检测出数据库的变更,然后自动更新缓存,特别是不使用二级缓存的情况下。个人理解,缓存只应缓存小容量数据(例如键值,标题列表等)而不存储大容量内容(例如帖子内容) 关于索引。只要被索引的列(例如回复表的标题ID)不被频繁更新,即使索引所在地行的其它列被频繁update,索引也不会被更新从而产生性能消耗,一张表一天30万次的索引更新,因它引起的性能消耗小到即使数据库安装在奔腾3单核CPU下都能轻松承担下来, 为什么会有人对索引有这么大的误解呢?。对一个论坛(或者绝大部分的系统)来说,检索(SELECT)数据耗费的系统资源远远高于更新数据(INSERT/UPDATE)本身,而索引是专门为检索数据服务的,难道就为了节省更新数据的小小的性能消耗,付出检索100条数据时需要数据库扫描几千万上亿条数据进行数据匹配的代价?如果是这样的话,即使是有32核顶级CPU的数据库作并行查询都未必顶得住。 做数据库设计,还是多了解数据库的原理才好。 你说的建立一个标题表和一个内容表。用户刚进来的时候看到的的确只有标题,这个时候不需要显示帖子内容,但是当用户查看帖子内容的时候,还得要访问一次数据库,IO访问是最消耗时间的,为什么不一次性将帖子加载到内存中呢或者将一部分比较火的帖子加载到内存中呢?你这样做只是减少了内存的占有量,但是,目前来说,内存应该不是问题吧,最主要的还是IO访问的耗时问题。 我觉得设计三张表是最好的 一张 user 一张 topics 一张 reverts,利用缓存来将经常被访问的帖子留在内存中,为每条缓存的记录添加一个访问时间,如果长时间没被访问就从缓存中删除掉,避免内存过大,每次用户看帖的时候,首先检索缓存中时候有需要的帖子,没有的话再访问数据库,然后将数据库返回的帖子信息存储到缓存中。 |
|
返回顶楼 | |
发表时间:2009-07-03
一,建库
1关系分析:1个用户能发多个帖子,1篇帖子可以发多个回复. 用户对帖子是1对多关系 ,帖子和回复是1对多的关系 2建表: 用户表: 用户id(主键),包含所有用户信息,帖子计数(尽量避免使用聚合函数使用触发器物理写入). 帖子表:标题,内容,用户id,(帖子id )主键,时间,回复计数(尽量避免使用聚合函数使用触发器物理写入)回复内容表:流水码(自增),帖子id,用户id(或用户名称),帖子内容,时间."根据环境建立主键方案很多 这里建立流水码为主键帖子id建索引" 二,代码优化 1尽量避免表的连接约束通过代码来实现约束 例如用户id的验证在用户登录时验证这样就可以把帖子表的用户id外键去掉这样就成了单表操作、查询 而连接可以通过触发来实现这样最多是查询了3个表而不是连接中的笛卡尔笛卡尔积 回复表的查询限定每次查询的记录数例如限定10条其它的通过点击触发来操作"注代码优化容易出现bug 原因有些开发工具本身有优化" 三,数据库性能调优 尽量用硬件来代替软件优化 原则就是能用硬件的尽量用硬件 比如磁盘阵列 RAID0 有条件用RAID10 加大内存 .避免小表上建索引 对论坛来说数据帖子和回复不是很重要 可以定期删除一些垃圾帖子 楼主说的几百万条记录的论坛对现在的数据库管理系统和计算机来说永不着刻意的优化,定期维护打包备份数据库就可以了 |
|
返回顶楼 | |
发表时间:2010-03-04
shuai45 写道 论坛访问量300万左右,更新帖子10万左右.
如果采用"直读","直写"的方法,显然压力全部在数据库上。频繁的数据库操作,频繁的查询和插入结果就不用说了。 我认为缓解数据库压力才是王道。至于表的设计,我想是次要的。我的想法如下: 1、数据库索引必须要建,增加查询速度。 2、在数据库和用户之间建立一个缓冲区。(如,将更新的数据放到内存中,达到一定数量的时候再统一更新数据库。假如以100条为例,一旦内存中达到100条数据量将这100条数据统一入库。减少insert操作) 3、在显示的时候也很重要。我的想法是假如用户第一次打开某标题,那将此标题的相关的前100条数据缓存到客户断。。。 。。。这样避开对数据库的直接查询,减少数据库压力。 以上方法可能欠妥。但必须通过第三方去实现,直来直去的时候,以这样的需求,实不可行 很同意你的说法 |
|
返回顶楼 | |