1. 程式人生 > >左右值編碼實現樹狀存儲

左右值編碼實現樹狀存儲

pid 遍歷 提高效率 body href 節點類 site 存儲 ges

聊聊樹狀結構如何在數據庫中存儲

昨天有人在QQ小組問起,無限分層的樹狀結構,數據量比較大,在一萬條以上,如何設計數據庫的結構。其實這是個老生常談的問題,一般的做法是有一個pid字段,為了提高效率,還會有個FullPath字段。(一些人還設置一個層級字段,但我不知道這個字段有何作用),FullPath字段可以用id-id-id….這種方式拼字符串存儲,這樣可以方便地用 like 語句進行查詢某個節點及其子節點。

曾經看到過另外一種存儲方式,利用了一般樹結構可以轉換二叉樹的這一做法,用二叉樹進行存儲,在數據量大的情況下,存儲讀效率比上述的常見方案更優些,所以特寫此文簡單介紹一番。

下圖說明了這種方案

技術分享

如圖所示,在每個節點上,有left ,right兩個字段,我們看到,圖上從根節點順著子節點開始畫一條線,每深入一層left加一,到底後,right=left+1,然後順著節點回溯,right逐級加一,一直回到根節點。

如果要查詢某個節點及其子節點,比如 fruit 節點 ,條件為 where left between 2 and 11

要查某個節點的full path ,比如 banana,條件為 where left<8 and right >9

如果要插入某個節點,比如red yellow直接插入一個節點,則update left =left+2 where left>=7 ,update right=right+2 where right>7,然後 新節點的left rigt分別是 7,8。 刪除節點類似。

這種方式,因為id都是int型數據,加上索引後,讀的效率較高。而fullPath字段的方案查詢時候用的是字符串操作like,效率較低。

在內存中,如果要還原樹狀結構,即在每個節點上增加pid屬性和children屬性,則稍微麻煩些,可以如下操作:

1 按left between x and y order by left 取數據

2 順序遍歷數據,如果left=上一個Left+1,則是上一個節點的子節點,設置兩個對象的父子關系,(【抱歉,這裏錯誤的,感謝“看風景的人”指出。】 如果發生跳號,則是上一個節點的兄弟節點。) 【這樣才是正確的】 如果發生跳號,說明這個節點不是上節點的子節點,向上回溯,找到right編號為當前節點left-1的,這個新找到的節點就是當前節點的兄弟。 比如 cherry(4,5)的下一個節點Yellow(7,10),向上找到red(3,6)為兄弟,meat(12,17)則向上找到 fruit(2,11)為兄弟。

3 如果要按水平查找兄弟節點,比如第二層,第一個節點為 fruit(2,11),然後向下查找,right=11,查找left=12的即為下一個兄弟節點。

OK,大致的方案就介紹到這裏,下面是參考地址

Storing Hierarchical Data in a Database Article

http://www.cnblogs.com/honghuamin/archive/2011/07/24/2115635.html

順便說一下,jqgrid的treegrid支持這種數據結構。

左右值編碼實現樹狀存儲