樹(shù)形結(jié)構(gòu)SQL結(jié)構(gòu)設(shè)計(jì)

業(yè)務(wù)中經(jīng)常有一些樹(shù)形結(jié)構(gòu)設(shè)計(jì),比如公司的組織架構(gòu)、服務(wù)調(diào)用鏈路等,每個(gè)節(jié)點(diǎn)都有子節(jié)點(diǎn)和父節(jié)點(diǎn),樹(shù)的深度又是不確定的,這時(shí)候sql結(jié)構(gòu)該怎么設(shè)計(jì)呢?

1、路徑枚舉模型

在這種模型中,我們?yōu)槊總€(gè)節(jié)點(diǎn)存儲(chǔ)一個(gè)字符串路徑,表示從根節(jié)點(diǎn)到該節(jié)點(diǎn)的路徑。例如,1/3/7 表示節(jié)點(diǎn)7是節(jié)點(diǎn)3的子節(jié)點(diǎn),而節(jié)點(diǎn)3又是節(jié)點(diǎn)1的子節(jié)點(diǎn)。

create table org (
id int(11),
name varcher(32),
parent_id int(11),
path varchar(100)
);

這種方法簡(jiǎn)單直觀,但當(dāng)樹(shù)變得很大或很深時(shí),路徑可能會(huì)變得非常長(zhǎng)。

1.1 查詢某個(gè)節(jié)點(diǎn)的所有子節(jié)點(diǎn)

SELECT * FROM org WHERE path LIKE '1/2/%/'
// 1/2/ 為某個(gè)節(jié)點(diǎn)的path路徑

1.2 查詢某個(gè)節(jié)點(diǎn)的所有父節(jié)點(diǎn)

// 查詢1/2/10的所有祖先
SELECT * FROM org WHERE "1/2/10/" LIKE path + '%' 

1.3 更新節(jié)點(diǎn)的路徑

//組織結(jié)構(gòu)變更,
UPDATE org SET path = REPLACE(path, '1/2/', '1/2/10/') WHERE path LIKE '1/2/%';

2、閉包模型

閉包模型是一個(gè)專門(mén)為存儲(chǔ)樹(shù)形結(jié)構(gòu)而設(shè)計(jì)的表。
包含一張節(jié)點(diǎn)基礎(chǔ)信息表,以及 一個(gè)包含節(jié)點(diǎn)與其所有祖先節(jié)點(diǎn)之間關(guān)系的關(guān)系列表;

這種方法允許你高效地查詢?nèi)魏蝺蓚€(gè)節(jié)點(diǎn)之間的所有路徑。

create table org(
id int(11),
name varcher(32)
);

create table org_node (
id int(11),
parent_id int(11),
child_id int(11),
depth int(4) commit '從祖先到后代的深度'
);

2.1 刪除節(jié)點(diǎn)的所有子節(jié)點(diǎn)

DELETE FROM org_node WHERE parent_id = 2

2.2 查詢節(jié)點(diǎn)的所有子節(jié)點(diǎn)

SELECT n.id, n.name
FROM org n
JOIN org_node c ON n.id = c.child_id 
WHERE c.parent_id = 1 AND c.depth > 0;

2.3 新增節(jié)點(diǎn)

//如果要給CTO增加一個(gè)MGR2成員,則需要進(jìn)行以下操作:

//1、為MGR2分配一個(gè)唯一的ID,并將其添加到nodes表中。
INSERT INTO org (name) VALUES ('MGR2'); //ID=10

//2、在closure表中插入自身的節(jié)點(diǎn)
INSERT INTO org_node (10, 10, 0)
//3、添加新的記錄到closure表中,以捕獲CTO與MGR2之間的關(guān)系。在此示例中,CTO是祖先,MGR2是后代,因此我們需要在org_node表中添加一條記錄,其中parent_id是CTO的ID,child_id是MGR2的ID,depth為2

INSERT INTO org_node (parend_id, child_id, depth)
SELECT a.parend_id, d.child_id, a.depth + d.depth + 1
FROM org_node a, org_node d
WHERE a.child_id = 2 AND d.parend_id = 10;

3、嵌套集模型

就是最簡(jiǎn)單的樹(shù)形結(jié)構(gòu),org表包含節(jié)點(diǎn)的id、名稱等屬性。關(guān)系表org_node 用來(lái)存儲(chǔ)節(jié)點(diǎn)之間的關(guān)系,其中每一行記錄包含一個(gè)祖先節(jié)點(diǎn)和一個(gè)后代節(jié)點(diǎn)的id,它們之間建立了一條從祖先到后代的路徑。

create table org(
id int(11),
name varcher(32)
);

create table org_node (
id int(11),
parent_id int(11),
child_id int(11),
);

3.1 統(tǒng)計(jì)一個(gè)節(jié)點(diǎn)的所有子節(jié)點(diǎn)

SELECT child.*
FROM org AS parent
JOIN org_node relationships ON parent.id = relationships.parent_id
JOIN nodes AS child ON relationships.child_id= child.id
WHERE parent.id = ?

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

// 新建一個(gè)節(jié)點(diǎn)
INSERT INTO org (name) VALUES ('new_node');

// 添加新節(jié)點(diǎn)和其父節(jié)點(diǎn)之間的關(guān)系
INSERT INTO org_node(parent_id, child_id)
SELECT parent.id, new_node.id
FROM org  AS parent
WHERE parent.name = 'parent_node'
CROSS JOIN org  AS new_node
WHERE new_node.name = 'new_node';

3.2 查看一個(gè)節(jié)點(diǎn)下所有下屬的節(jié)點(diǎn)

//需要遞歸查詢

3.3 刪除一個(gè)節(jié)點(diǎn)的所有后續(xù)節(jié)點(diǎn)

//遞歸刪除 

4、 優(yōu)缺點(diǎn)對(duì)比

4.1 路徑枚舉

  • 優(yōu)點(diǎn)
    查詢節(jié)點(diǎn)的所有祖先和后代節(jié)點(diǎn)更高效;
    層級(jí)深度易于確定;

  • 缺點(diǎn)
    更新節(jié)點(diǎn)需要更新大量的關(guān)系數(shù)據(jù);
    數(shù)據(jù)增加時(shí)占用存儲(chǔ)空間更大;

數(shù)據(jù)完整性無(wú)法保證;

4.2 閉包

  • 優(yōu)點(diǎn)
    不需要遞歸操作;
    查詢節(jié)點(diǎn)的所有祖先和后代節(jié)點(diǎn)更高效;
    層級(jí)深度易于確定;

  • 缺點(diǎn)
    更新節(jié)點(diǎn)需要更新大量的關(guān)系數(shù)據(jù);
    層級(jí)深度大時(shí),數(shù)據(jù)增加時(shí)占用存儲(chǔ)空間更大

4.3 嵌套集

  • 優(yōu)點(diǎn)
    簡(jiǎn)單易懂,易于實(shí)現(xiàn);
    節(jié)點(diǎn)查詢和遍歷相對(duì)容易;

  • 缺點(diǎn)
    刪除或更新節(jié)點(diǎn)需要遞歸操作,性能可能不佳;
    節(jié)點(diǎn)的層級(jí)深度不易確定;

從工作中實(shí)踐來(lái)看,對(duì)于節(jié)點(diǎn)關(guān)系比較復(fù)雜的場(chǎng)景(比如,對(duì)于不同節(jié)點(diǎn)權(quán)限的控制),使用嵌套集模型是最優(yōu)的,不需要像嵌套集一樣總是遞歸操作,也不用像閉包模型一樣考慮數(shù)量太大的問(wèn)題。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容