樹型論壇的數據庫設計和快速算法

 樹型論壇(即階梯式論壇)的實現算法,是一直被討論的問題。總結起來,一般無非是兩種:  
 第一是遞歸。這種方式最簡單,思路最清楚,但是效率也最低,特別是進行頁定位的時候。由於每進行一次遞歸調用,就必須執行一條數據庫查詢,使它在大量併發請求時的負載成爲災難性的。因此這種算法一般不實用。  
 第二是增加一個排序字段,思路是使用一個特殊設計的字段,例如排序串或者中值排序基數,來實現貼子的插入,在顯示的時候,只需要爲每一個主貼執行一次查詢,將所有得到的記錄按序顯示即可。這種方式在效率上有了很大提高,但是仍然不很理想,而且使得插入的代碼增加了不必要的複雜性,同時還往往導致了支持層次有限制的問題。  
 
有沒有一種辦法可以簡單、高效地實現樹型論壇呢?  
 
左輕侯提出一種算法,在顯示速度上超過我見的任何類似算法,實現起來也不復雜。  
它的思路很簡單:就是完全不理會樹型結構本身,將整個論壇視爲一個簡單的順序表。這樣不論任何形式的頁面,只需要一條查詢即可得到。那麼如何實現樹型結構呢?方法是添加兩個格式化字段,一個記錄順序表的次序,一個記錄樹的層次,對取得的記錄集進行相應格式化,即可得到原汁原味的樹型論壇。  
 
我的改進是,  
               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字段。但是經驗告訴我們,這種樹型論壇,回覆一般都集中在第一二頁,極少有人回覆很久以前的貼子,所以偶爾爲之,也不會增加太大的負擔。如果你實在不放心,也可以用技術手段強制禁止回覆一段時間  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章