日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

树形结构表3种设计分析分享

發布時間:2024/1/4 综合教程 28 生活家
生活随笔 收集整理的這篇文章主要介紹了 树形结构表3种设计分析分享 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

簡介

在開發中經常遇到樹形結構的場景,本文將以部門表為例對比幾種設計的優缺點;

問題

需求背景:根據部門檢索人員,
問題:選擇一個頂級部門情況下,跨級展示當前部門以及子部門下的所有人員,表怎么設計更合理 ?


遞歸嗎 ?遞歸可以解決,但是勢必消耗性能
設計1:鄰接表

注:(常見父Id設計)

表設計

1 CREATE TABLE `dept_info01` (
2 `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主鍵',
3 `dept_id` int(10) NOT NULL COMMENT '部門id',
4 `dept_name` varchar(100) NOT NULL COMMENT '部門名稱',
5 `dept_parent_id` int(11) NOT NULL COMMENT '父部門id',
6 `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創建時間',
7 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改時間',
8 PRIMARY KEY (`id`) USING BTREE
9 ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

這樣是最常見的設計,能正確的表達菜單的樹狀結構且沒有冗余數據,但在跨層級查詢需要遞歸處理。

SQL示例

1.查詢某一個節點的直接子集

SELECT * FROM dept_info01 WHERE dept_parent_id =1001

優點

結構簡單 ;
缺點

1.不使用遞歸情況下無法查詢某節點所有父級,所有子集

設計2:路徑枚舉

在設計1基礎上新增一個父部門id集字段,用來存儲所有父集,多個以固定分隔符分隔,比如逗號。

表設計

CREATE TABLE `dept_info02` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主鍵',
`dept_id` int(10) NOT NULL COMMENT '部門id',
`dept_name` varchar(100) NOT NULL COMMENT '部門名稱',
`dept_parent_id` int(11) NOT NULL COMMENT '父部門id',
`dept_parent_ids` varchar(255) NOT NULL DEFAULT '' COMMENT '父部門id集',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創建時間',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改時間',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;


SQL示例

1.查詢所有子集
1).通過模糊查詢

SELECT
*
FROM
dept_info02
WHERE
dept_parent_ids like '%1001%'

2).推薦使用 FIND_IN_SET 函數

SELECT
* 
FROM
dept_info02 
WHERE
FIND_IN_SET( '1001', dept_parent_ids )

優點

方便查詢所有的子集 ;
可以因此通過比較字符串dept_parent_ids長度獲取當前節點層級 ;

### 缺點
新增節點時需要將dept_parent_ids字段值處理好 ;
dept_parent_ids字段的長度很難確定,無論長度設為多大,都存在不能夠無限擴展的情況 ;
節點移動復雜,需要同時變更所有子集中的dept_parent_ids字段值 ;

設計2:閉包表

閉包表是解決分級存儲的一個簡單而優雅的解決方案,這是一種通過空間換取時間的方式 ;
需要額外創建了一張TreePaths表它記錄了樹中所有節點間的關系 ;
包含兩列,祖先列與后代列,即使這兩個節點之間不是直接的父子關系;同時增加一行指向節點自己 ;
表設計

主表

CREATE TABLE `dept_info03` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主鍵',
`dept_id` int(10) NOT NULL COMMENT '部門id',
`dept_name` varchar(100) NOT NULL COMMENT '部門名稱',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創建時間',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改時間',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;


祖先后代關系表

CREATE TABLE `dept_tree_path_info` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主鍵',
`ancestor` int(10) NOT NULL COMMENT '祖先id',
`descendant` int(10) NOT NULL COMMENT '后代id',
`depth` tinyint(4) NOT NULL DEFAULT '0' COMMENT '層級深度',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

注:depth 層級深度字段 ,自我引用為 1,直接子節點為 2,再一下層為 3,一次類推,第幾層就是幾 。

SQL示例

插入新節點

INSERT INTO dept_tree_path_info (ancestor, descendant,depth)
SELECT t.ancestor, 3001,t.depth+1 FROM dept_tree_path_info AS t 
WHERE t.descendant = 2001
UNION ALL
SELECT 3001,3001,1

查詢所有祖先

SELECT
c.*
FROM
dept_info03 AS c
INNER JOIN dept_tree_path_info t ON c.dept_id = t.ancestor
WHERE
t.descendant = 3001

查詢所有后代

SELECT
c.*
FROM
dept_info03 AS c
INNER JOIN dept_tree_path_info t ON c.dept_id = t.descendant
WHERE
t.ancestor = 1001

刪除所有子樹

DELETE 
FROM
dept_tree_path_info 
WHERE
descendant IN 
( 
SELECT
a.dept_id 
FROM
( SELECT descendant dept_id FROM dept_tree_path_info WHERE ancestor = 1001 ) a
)

刪除葉子節點

DELETE 
FROM
dept_tree_path_info 
WHERE
descendant = 2001

移動節點

刪除所有子樹(先斷開與原祖先的關系)
建立新的關系
優點

非遞歸查詢減少冗余的計算時間 ;
方便非遞歸查詢任意節點所有的父集 ;
方便查詢任意節點所有的子集 ;
可以實現無限層級 ;
支持移動節點 ;

### 缺點
層級太多情況下移動樹節點會帶來關系表多條操作 ;
需要單獨一張表存儲對應關系,在新增與編輯節點時操作相對復雜 ;
結合使用

可以將鄰接表方式與閉包表方式相結合使用。實際上就是將父id冗余到主表中,在一些只需要查詢直接關系的業務中就可以直接查詢主表,而不需要關聯2張表了。在需要跨級查詢時祖先后代關系表就顯得尤為重要。

表設計

主表

CREATE TABLE `dept_info04` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主鍵',
`dept_id` int(10) NOT NULL COMMENT '部門id',
`dept_name` varchar(100) NOT NULL COMMENT '部門名稱',
`dept_parent_id` int(11) NOT NULL COMMENT '父部門id',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創建時間',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改時間',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

祖先后代關系表

CREATE TABLE `dept_tree_path_info` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主鍵',
`ancestor` int(10) NOT NULL COMMENT '祖先id',
`descendant` int(10) NOT NULL COMMENT '后代id',
`depth` tinyint(4) NOT NULL DEFAULT '0' COMMENT '層級深度',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

總結

其實,在以往的工作中,曾見過不同類型的設計,鄰接表,路徑枚舉,鄰接表路徑枚舉一起來的都見過。每種設計都各有優劣,如果選擇設計依賴于應用程序中哪種操作最需要性能上的優化。

設計 表數量 查詢直接子 查詢子樹 同時查詢多個節點子樹 插入 刪除 移動
鄰接表 1 簡單 需要遞歸 需要遞歸 簡單 簡單 簡單
枚舉路徑 1 簡單 簡單 查多次 相對復雜 簡單 復雜
閉包表 2 簡單 簡單 簡單 相對復雜 簡單 復雜

綜上所述

只需要建立子父集關系中可以使用鄰接表方式 ;
涉及向上查找,向下查找的需要建議使用閉包表方式 ;
————————————————
版權聲明:本文為CSDN博主「程序員小強」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qq_38011415/article/details/95462698

總結

以上是生活随笔為你收集整理的树形结构表3种设计分析分享的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。