树状结构表结构和功能设计
在我們開發(fā)過程中經(jīng)常會遇到各種組織樹結(jié)構(gòu),比如我們的公司人員結(jié)構(gòu),權(quán)限資源的管理,等等。而我們這些數(shù)據(jù)落到表里面是以一條條數(shù)據(jù)構(gòu)成的,我們存儲資源時按照一條條存儲是非常簡單的,但是在操作資源構(gòu)建樹的時候往往會碰到很多問題,下面我們以一條實例來探討組織樹資源的表結(jié)構(gòu)設(shè)計和功能點。
表結(jié)構(gòu)設(shè)計(以mysql為基礎(chǔ))
我們要設(shè)計一個樹狀結(jié)構(gòu)的數(shù)據(jù)存儲,第一反應(yīng)是在表里面加一個parent_id
這肯定沒有錯,我們通過數(shù)據(jù)的id和parent_id就能組裝成整個的樹結(jié)構(gòu),但是比如我們的需求往往不是這么簡單,比如我需要關(guān)注節(jié)點的狀態(tài),根據(jù)狀態(tài)去做圖標的顯示和功能的限制,那么我們就需要添加一個status字段
同時我們的樹不可能無限制構(gòu)建,遞歸是一個非常消耗資源的事情,所以我們需要限制樹的高度,這里我們可以通過加入一個level字段去控制樹的層級
也可能我們有這樣的需求,我們關(guān)心節(jié)點之間的順序,于是我們又要添加一個order_num來控制排序
綜合上述,我們得出一張這樣的表結(jié)構(gòu)
| id | int(11) | 主鍵 | 是 | 是 |
| parent_id | int(11) | 父id | 否 | 是 |
| level | tinyint(2) | 層級 | 否 | 是 |
| parent_path | varchar(640) | 當前節(jié)點在樹節(jié)點中的路徑,以/分割,如0/1/2/ | 否 | 是 |
| name | varchar(255) | 名稱 | 否 | 否 |
| status | tinyint | 是否啟用 | 否 | 是 |
| order_num | int(5) | 順序 | 否 | 是 |
字段的用途大家都應(yīng)該明白,但是這里有個parent_path有點迷糊,在樹結(jié)構(gòu)的環(huán)境下往往有這么個需求,查找某個節(jié)點的所有子節(jié)點,如此,按照一般思路我們需要遞歸去查詢,對數(shù)據(jù)庫造成的性能損失
這里我們引入了parent_path字段,每次需要查詢子節(jié)點的時候,只需要執(zhí)行sql:
當然還有一種思路是path按照逗號分割(0,1,2),這樣我們可以直接使用mysql的內(nèi)置函數(shù)FIND_IN_SET
SELECT id from tree_test where FIND_IN_SET('1',path);但是,通過我們查看執(zhí)行計劃,like的方式可以走索引,而FIND_IN_SET不會走,所以我們選擇like的方式。
你以為到這里就結(jié)束啦,當然沒有,節(jié)點的順序除了同節(jié)點間的交換插入,可能從其他層級進入當前層級,或者從當前層級擴散到其他層級,萬物都是一把雙刃劍,parent_path給我們帶來方便的同時,我們每次在節(jié)點移動的時候需要變更這個path,增加了一定的工作量。
那么我們在挪動節(jié)點的時候,順序是怎么維護的呢?
功能設(shè)計
我整理了一個圖,其中x表示元素的起始順序,y表示元素的目標順序,當我們在節(jié)點進行變更時需要按照一下規(guī)則維護order_num字段
以上就是我針對樹狀數(shù)據(jù)開發(fā)過程中可能遇到的點,如果還有需要解決的問題歡迎在評論區(qū)留言。
總結(jié)
以上是生活随笔為你收集整理的树状结构表结构和功能设计的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 推荐一款全能PDF编辑神器:PDFele
- 下一篇: 七、树状结构