最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談MYSQL中樹形結(jié)構(gòu)表3種設(shè)計(jì)優(yōu)劣分析與分享

 更新時(shí)間:2021年09月22日 10:32:33   作者:程序員小強(qiáng)  
在開發(fā)中經(jīng)常遇到樹形結(jié)構(gòu)的場(chǎng)景,本文將以部門表為例對(duì)比幾種設(shè)計(jì)的優(yōu)缺點(diǎn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

簡(jiǎn)介

在開發(fā)中經(jīng)常遇到樹形結(jié)構(gòu)的場(chǎng)景,本文將以部門表為例對(duì)比幾種設(shè)計(jì)的優(yōu)缺點(diǎn);

問題

需求背景:根據(jù)部門檢索人員,
問題:選擇一個(gè)頂級(jí)部門情況下,跨級(jí)展示當(dāng)前部門以及子部門下的所有人員,表怎么設(shè)計(jì)更合理 ?

image.png

遞歸嗎 ?遞歸可以解決,但是勢(shì)必消耗性能

設(shè)計(jì)1:鄰接表

注:(常見父Id設(shè)計(jì))

表設(shè)計(jì)

CREATE TABLE `dept_info01` (
  `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 '創(chuàng)建時(shí)間',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改時(shí)間',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

image.png

這樣是最常見的設(shè)計(jì),能正確的表達(dá)菜單的樹狀結(jié)構(gòu)且沒有冗余數(shù)據(jù),但在跨層級(jí)查詢需要遞歸處理。

SQL示例

1.查詢某一個(gè)節(jié)點(diǎn)的直接子集

SELECT * FROM dept_info01  WHERE dept_parent_id =1001

優(yōu)點(diǎn)

結(jié)構(gòu)簡(jiǎn)單 ;

缺點(diǎn)

1.不使用遞歸情況下無(wú)法查詢某節(jié)點(diǎn)所有父級(jí),所有子集

設(shè)計(jì)2:路徑枚舉

在設(shè)計(jì)1基礎(chǔ)上新增一個(gè)父部門id集字段,用來(lái)存儲(chǔ)所有父集,多個(gè)以固定分隔符分隔,比如逗號(hào)。

表設(shè)計(jì)

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 '創(chuàng)建時(shí)間',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改時(shí)間',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

image.png

SQL示例

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

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

2).推薦使用 FIND_IN_SET 函數(shù)

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

優(yōu)點(diǎn)

  • 方便查詢所有的子集 ;
  • 可以因此通過比較字符串dept_parent_ids長(zhǎng)度獲取當(dāng)前節(jié)點(diǎn)層級(jí) ;

缺點(diǎn)

  • 新增節(jié)點(diǎn)時(shí)需要將dept_parent_ids字段值處理好 ;
  • dept_parent_ids字段的長(zhǎng)度很難確定,無(wú)論長(zhǎng)度設(shè)為多大,都存在不能夠無(wú)限擴(kuò)展的情況 ;節(jié)
  • 點(diǎn)移動(dòng)復(fù)雜,需要同時(shí)變更所有子集中的dept_parent_ids字段值 ;

設(shè)計(jì)3:閉包表

  • 閉包表是解決分級(jí)存儲(chǔ)的一個(gè)簡(jiǎn)單而優(yōu)雅的解決方案,這是一種通過空間換取時(shí)間的方式 ;
  • 需要額外創(chuàng)建了一張TreePaths表它記錄了樹中所有節(jié)點(diǎn)間的關(guān)系 ;
  • 包含兩列,祖先列與后代列,即使這兩個(gè)節(jié)點(diǎn)之間不是直接的父子關(guān)系;同時(shí)增加一行指向節(jié)點(diǎn)自己 ;

表設(shè)計(jì)

主表

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 '創(chuàng)建時(shí)間',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改時(shí)間',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

image.png

祖先后代關(guān)系表

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 '層級(jí)深度',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

注:depth 層級(jí)深度字段 ,自我引用為 1,直接子節(jié)點(diǎn)為 2,再一下層為 3,一次類推,第幾層就是幾 。

image.png

SQL示例

插入新節(jié)點(diǎn)

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
	)

刪除葉子節(jié)點(diǎn)

DELETE 
FROM
	dept_tree_path_info 
WHERE
	descendant = 2001

移動(dòng)節(jié)點(diǎn)

  • 刪除所有子樹(先斷開與原祖先的關(guān)系)
  • 建立新的關(guān)系

優(yōu)點(diǎn)

  • 非遞歸查詢減少冗余的計(jì)算時(shí)間 ;
  • 方便非遞歸查詢?nèi)我夤?jié)點(diǎn)所有的父集 ;
  • 方便查詢?nèi)我夤?jié)點(diǎn)所有的子集 ;
  • 可以實(shí)現(xiàn)無(wú)限層級(jí) ;
  • 支持移動(dòng)節(jié)點(diǎn) ; 

缺點(diǎn)

  • 層級(jí)太多情況下移動(dòng)樹節(jié)點(diǎn)會(huì)帶來(lái)關(guān)系表多條操作 ;
  • 需要單獨(dú)一張表存儲(chǔ)對(duì)應(yīng)關(guān)系,在新增與編輯節(jié)點(diǎn)時(shí)操作相對(duì)復(fù)雜 ;

結(jié)合使用

可以將鄰接表方式與閉包表方式相結(jié)合使用。實(shí)際上就是將父id冗余到主表中,在一些只需要查詢直接關(guān)系的業(yè)務(wù)中就可以直接查詢主表,而不需要關(guān)聯(lián)2張表了。在需要跨級(jí)查詢時(shí)祖先后代關(guān)系表就顯得尤為重要。

表設(shè)計(jì)

主表

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 '創(chuàng)建時(shí)間',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改時(shí)間',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

祖先后代關(guān)系表

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 '層級(jí)深度',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

總結(jié)

其實(shí),在以往的工作中,曾見過不同類型的設(shè)計(jì),鄰接表,路徑枚舉,鄰接表路徑枚舉一起來(lái)的都見過。每種設(shè)計(jì)都各有優(yōu)劣,如果選擇設(shè)計(jì)依賴于應(yīng)用程序中哪種操作最需要性能上的優(yōu)化。

設(shè)計(jì) 表數(shù)量 查詢直接子 查詢子樹 同時(shí)查詢多個(gè)節(jié)點(diǎn)子樹 插入 刪除 移動(dòng)
鄰接表 1 簡(jiǎn)單 需要遞歸 需要遞歸 簡(jiǎn)單 簡(jiǎn)單 簡(jiǎn)單
枚舉路徑 1 簡(jiǎn)單 簡(jiǎn)單 查多次 相對(duì)復(fù)雜 簡(jiǎn)單 復(fù)雜
閉包表 2 簡(jiǎn)單 簡(jiǎn)單 簡(jiǎn)單 相對(duì)復(fù)雜 簡(jiǎn)單 復(fù)雜

綜上所述

  • 只需要建立子父集關(guān)系中可以使用鄰接表方式 ;
  • 涉及向上查找,向下查找的需要建議使用閉包表方式 ;

到此這篇關(guān)于淺談MYSQL中樹形結(jié)構(gòu)表3種設(shè)計(jì)優(yōu)劣分析與分享的文章就介紹到這了,更多相關(guān)MYSQL 樹形結(jié)構(gòu)表內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • mysql?sock?文件解析及作用講解

    mysql?sock?文件解析及作用講解

    這篇文章主要為大家介紹了mysql.sock?文件解析及作用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • 詳解MySQL的Seconds_Behind_Master

    詳解MySQL的Seconds_Behind_Master

    對(duì)于mysql主備實(shí)例,seconds_behind_master是衡量master與slave之間延時(shí)的一個(gè)重要參數(shù)。通過在slave上執(zhí)行"show slave status;"可以獲取seconds_behind_master的值。
    2021-05-05
  • mysql表的基礎(chǔ)操作匯總(三)

    mysql表的基礎(chǔ)操作匯總(三)

    這篇文章主要匯總了針對(duì)mysql表進(jìn)行的相關(guān)基礎(chǔ)操作,具有一定的實(shí)用性,供大家參考,感興趣的小伙伴們可以參考一下
    2016-08-08
  • mysql慢查詢操作實(shí)例分析【開啟、測(cè)試、確認(rèn)等】

    mysql慢查詢操作實(shí)例分析【開啟、測(cè)試、確認(rèn)等】

    這篇文章主要介紹了mysql慢查詢操作,結(jié)合實(shí)例形式分析了mysql慢查詢操作中的開啟、測(cè)試、確認(rèn)等實(shí)現(xiàn)方法及相關(guān)操作技巧,需要的朋友可以參考下
    2019-12-12
  • linux下perl操作mysql數(shù)據(jù)庫(kù)(需要安裝DBI)

    linux下perl操作mysql數(shù)據(jù)庫(kù)(需要安裝DBI)

    有時(shí)候需要perl操作mysql數(shù)據(jù)庫(kù),可以通過DBI實(shí)現(xiàn),需要的朋友可以參考下
    2012-05-05
  • MySQL如何改變表的存儲(chǔ)引擎方式

    MySQL如何改變表的存儲(chǔ)引擎方式

    這篇文章主要介紹了MySQL如何改變表的存儲(chǔ)引擎方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • MySQL數(shù)據(jù)庫(kù)本地事務(wù)原理解析

    MySQL數(shù)據(jù)庫(kù)本地事務(wù)原理解析

    事務(wù)是數(shù)據(jù)庫(kù)系統(tǒng)中的重要概念,了解這一律念是以正確的方式開發(fā)和數(shù)據(jù)庫(kù)交互的應(yīng)用程序的前提,今天通過本文給大家介紹MySQL數(shù)據(jù)庫(kù)本地事務(wù)原理解析,感興趣的朋友一起看看吧
    2022-01-01
  • Mysql Binlog數(shù)據(jù)查看的方法詳解

    Mysql Binlog數(shù)據(jù)查看的方法詳解

    這篇文章主要介紹了Mysql Binlog數(shù)據(jù)查看的方法詳解,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-07-07
  • mysql如何利用Navicat導(dǎo)出和導(dǎo)入數(shù)據(jù)庫(kù)的方法

    mysql如何利用Navicat導(dǎo)出和導(dǎo)入數(shù)據(jù)庫(kù)的方法

    這篇文章主要介紹了mysql如何利用Navicat導(dǎo)出和導(dǎo)入數(shù)據(jù)庫(kù)的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧
    2019-02-02
  • 最新版MySQL 8.0.22下載安裝超詳細(xì)教程(Windows 64位)

    最新版MySQL 8.0.22下載安裝超詳細(xì)教程(Windows 64位)

    這篇文章主要介紹了最新版MySQL 8.0.22下載安裝超詳細(xì)教程(Windows 64位),本文通過圖文實(shí)例相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12

最新評(píng)論

武强县| 涪陵区| 仙桃市| 上蔡县| 嵊泗县| 通化县| 伊川县| 资源县| 行唐县| 合川市| 淳化县| 横峰县| 息烽县| 金秀| 南召县| 汽车| 汝州市| 阳春市| 恭城| 朝阳区| 汝南县| 唐河县| 襄樊市| 柘荣县| 常州市| 兴化市| 温州市| 东乌珠穆沁旗| 奉化市| 邯郸县| 固原市| 大厂| 石嘴山市| 庆城县| 景谷| 叙永县| 宁波市| 凤翔县| 墨玉县| 大邑县| 乐昌市|