• 树型论坛的数据库设计和快速算法


    树型论坛(即阶梯式论坛)的实现算法,是一直被讨论的问题。总结起来,一般无非是两种:  
     第一是递归。这种方式最简单,思路最清楚,但是效率也最低,特别是进行页定位的时候。由于每进行一次递归调用,就必须执行一条数据库查询,使它在大量并发请求时的负载成为灾难性的。因此这种算法一般不实用。  
     第二是增加一个排序字段,思路是使用一个特殊设计的字段,例如排序串或者中值排序基数,来实现贴子的插入,在显示的时候,只需要为每一个主贴执行一次查询,将所有得到的记录按序显示即可。这种方式在效率上有了很大提高,但是仍然不很理想,而且使得插入的代码增加了不必要的复杂性,同时还往往导致了支持层次有限制的问题。  
     
    有没有一种办法可以简单、高效地实现树型论坛呢?  
     
    左轻侯提出一种算法,在显示速度上超过我见的任何类似算法,实现起来也不复杂。  
    它的思路很简单:就是完全不理会树型结构本身,将整个论坛视为一个简单的顺序表。这样不论任何形式的页面,只需要一条查询即可得到。那么如何实现树型结构呢?方法是添加两个格式化字段,一个记录顺序表的次序,一个记录树的层次,对取得的记录集进行相应格式化,即可得到原汁原味的树型论坛。  
     
    我的改进是,  
                   1。取消ordernum,用messageID的顺序来实现,  
                   2。在BBSmessage表里面取消threadID的FK,用算法来映射  
                   3。在BBSthread表里面增设一个endMessageID来为最大MessageID,提高插入数据的速度  
     
     具体实现方法如下:  
     
    dbschema:  
     
    BBSmessage:                        贴子表  
           messageID      int                                  :  贴子ID  
           deep                smallint                        :  树的深度,0为主贴,以此类推  
           context          varchar  4096                :  正文  
           title              varchar  256                  :  标题  
           clickDate      timestamp                      :  阅读时间  
           createDate    timestamp                      :  创建时间(发布时间)  
           clickCnt        smallint                        :  人气  
           rewards          smallint                        :  得分  
           userID            int                                  :  创建用户ID  
           flag                char(1)                          :  标志    D=删除状态    A  =活跃状态  
    //    threadID        int                                  :  主题ID  =  messageID/1000  
     
    BBSthread:                            话题表  
           threadID                        int                  :  话题ID  
           forumID                          int                  :  所属论坛ID  
           clickDate                      timestamp      :  阅读时间  
           createDate                    timestamp      :  创建时间  
     
           clickSum                        smallint        :  话题人气  
           replySum                        smallint        :  回复数量  
           endMessageID                int                  :  尾部ID  
    //    rootMessageID              int                  :  该话题的根贴子ID,可以用threadID*1000得到rootMessageID  
    //    replyDate                      timestamp      :  最新回复时间,因为可以用lastMessageID得到时间  
    //    title                              vchar(20)      :  标题,可以用threadID*1000得到rootMessageID,再取得title  
     
    BBSUserInfo:                        用户表  
           userid                            int                  :  用户ID  
           userNickName                vchar  20        :  昵称  
           sex                                  char  (1)        :  性别  
           rewards                          smallint        :  得分  
           PostCnt                          smallint        :  一共发贴数  
           icon                                smallint        :  图标ID  
     
     
    列出全部话题列表的SQL:  
    //            主题          人气                创建人    最后更新时间  回复人  删除属性  
    select  title  ,  clickSum  ,  replyDate  ,  userName  ,  deep  ,  replySum,deep,visual  
           from  
                   BBSUserInfo,BBSthread,BBSmessage  
           where  
                   BBSmessage.userid  =  BBSUserInfo.userid  
                   and  
                   BBSmessage.messageID  =  BBSthread.rootMessageID  
                   and  
                   BBSthread.messageID  <  BBSthread.message+1000  
           order  by  messageID  desc  
     
     
    其中threadID  *  1000  =  rootMessageID,  
     
    对贴子的管理实现:  
         1.      树结构:  
         1.1    deep层,那么n层message就缩进n个tablelet  
         1.2    如果插入数据,那么就在thread表里面的endMessageID+1并以此为最新ID写入BBSmessage  
                   比左先生的select  max(ordernum)再添加效果好,因为这样是row级锁,而select  max()是表级锁。如果不加事务处理,必定有问题。因此,这点必须改进。  
                   中间插入操作分析:  
                   messageID由Thread表里面的threadID*1000得到,因此,这个动作是如同在一个顺序表里面插入数据一般。  
                   对此,我没有做改进,因为我认为左先生的分析已经很明确了。  
                   但是如果数据中间有+n个间隔,如0,5,10,的顺序,那么中间插入纪录的也许速度有所提高。但是这样有效贴子数就下降了。  
     
    例子:  
     └─api  (1000)  
             ├─java  (1001)  
             │    ├─                                --  1002已经被delete  
             │    ├─applet  (1003)--  del  1003,同时要delete  1004,  因为在(awt  1005  deep3)前有class-use(1004,deep4)  
             │    │    └─class-use  (1004)  
             │    ├─awt  (1005)    
             │    │    ├─class-use  (1006)    
             │    │    ├─color    (1007)  
             │    │    │    └─  new  !  <--  1008,  同时>1008都+1  
             │    │    ├─datatransfer  (1008)  
             │    │    │    └─class-use  (1009)    <--  new  
     
    =>  
     
     
     效率分析:  
     
    在message表中,  messageID并不是按顺序存放的,而是跳着存放,  
    系统限制没个话题总回贴数不能超过1000,那么一个long型数据在一个论坛里面可以最大支持2147483647/1000=2147483条记录  
    应该说,一张有214万7千左右的bbs数据库应该是很够用了。  
    如果系统还要大,那么就可以按时间段更换数据表即可实现无限量贴子。具体做法:如引入messagehistory2002表等等。  
     
    显示速度应该不会更快了,仅仅是一条简单的select,对一个int字段进行排序,而且支持无限的回复层次。相比之下,递归需要为一个页面中的每一条贴子进行一次select,对datetime字段进行排序,而“主贴排序字段法”需要为每一个主贴进行一次select,对char字段进行排序。效率比较差的只有在插入时,如果插入的位置很靠前,可能要更新大量记录的messageid字段。但是经验告诉我们,这种树型论坛,回复一般都集中在第一二页,极少有人回复很久以前的贴子,所以偶尔为之,也不会增加太大的负担。如果你实在不放心,也可以用技术手段强制禁止回复一段时间  

    http://blog.csdn.net/wangxiaobo23/archive/2006/09/12/1213978.aspx

  • 相关阅读:
    curl 带 body
    import com.sun.org.apache.xml.internal.security.utils.Base64问题
    动静分离业务解决网页请求不被串改
    java 主动信任证书
    IO 多路复用详解
    spanish-1.1
    spring data JPA entityManager查询 并将查询到的值转为实体对象
    微信二维码支付报错
    军训入营学生发言稿
    电位器控制两个 LED 灯交替闪烁
  • 原文地址:https://www.cnblogs.com/lmule/p/1802797.html
Copyright © 2020-2023  润新知