mysql的树形结构存储及查询实例分析

发布时间:2022-04-06 10:20:28 作者:iii
来源:亿速云 阅读:166

MySQL的树形结构存储及查询实例分析

引言

在数据库设计中,树形结构是一种常见的数据组织形式,广泛应用于分类、组织结构、评论回复等场景。MySQL作为一款流行的关系型数据库管理系统,虽然没有原生支持树形结构,但通过合理的设计和查询优化,依然可以高效地存储和查询树形数据。本文将深入探讨MySQL中树形结构的存储方式、查询方法以及性能优化策略,并通过实例分析帮助读者更好地理解和应用。

1. 树形结构的存储方式

在MySQL中,树形结构的存储主要有以下几种方式:

1.1 邻接表模型(Adjacency List Model)

邻接表模型是最常见的树形结构存储方式。在这种模型中,每个节点存储其父节点的ID,根节点的父节点ID通常为NULL。

表结构示例:

CREATE TABLE categories (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    parent_id INT,
    FOREIGN KEY (parent_id) REFERENCES categories(id)
);

优点: - 结构简单,易于理解和实现。 - 插入、删除节点操作方便。

缺点: - 查询子树或祖先节点时需要递归查询,性能较差。 - 查询深度较大的树时,递归查询会导致性能瓶颈。

1.2 路径枚举模型(Path Enumeration Model)

路径枚举模型通过存储每个节点的路径信息来表示树形结构。路径通常以字符串形式存储,包含从根节点到当前节点的所有祖先节点ID。

表结构示例:

CREATE TABLE categories (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    path VARCHAR(255)
);

优点: - 查询子树或祖先节点时,可以通过字符串匹配快速定位。 - 查询性能较好,尤其是在查询子树时。

缺点: - 插入、删除节点时需要更新路径信息,操作复杂。 - 路径长度有限,可能不适合深度较大的树。

1.3 嵌套集模型(Nested Set Model)

嵌套集模型通过为每个节点分配一个左值和右值来表示树形结构。左值和右值定义了节点在树中的位置关系。

表结构示例:

CREATE TABLE categories (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    lft INT NOT NULL,
    rgt INT NOT NULL
);

优点: - 查询子树或祖先节点时,可以通过范围查询快速定位。 - 查询性能较好,尤其是在查询子树时。

缺点: - 插入、删除节点时需要更新大量节点的左值和右值,操作复杂。 - 维护成本较高,尤其是在频繁插入、删除节点的场景中。

1.4 闭包表模型(Closure Table Model)

闭包表模型通过引入一个额外的表来存储节点之间的关系。这个表记录了每个节点与其所有祖先节点之间的关系。

表结构示例:

CREATE TABLE categories (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL
);

CREATE TABLE category_closure (
    ancestor INT NOT NULL,
    descendant INT NOT NULL,
    depth INT NOT NULL,
    PRIMARY KEY (ancestor, descendant),
    FOREIGN KEY (ancestor) REFERENCES categories(id),
    FOREIGN KEY (descendant) REFERENCES categories(id)
);

优点: - 查询子树或祖先节点时,可以通过简单的JOIN操作快速定位。 - 查询性能较好,尤其是在查询子树时。

缺点: - 需要额外的表来存储关系,增加了存储空间。 - 插入、删除节点时需要维护闭包表,操作复杂。

2. 树形结构的查询方法

不同的存储方式对应不同的查询方法。下面我们将分别介绍每种存储方式下的常见查询操作。

2.1 邻接表模型的查询

查询子树:

WITH RECURSIVE subcategories AS (
    SELECT id, name, parent_id
    FROM categories
    WHERE id = 1
    UNION ALL
    SELECT c.id, c.name, c.parent_id
    FROM categories c
    INNER JOIN subcategories s ON c.parent_id = s.id
)
SELECT * FROM subcategories;

查询祖先节点:

WITH RECURSIVE ancestors AS (
    SELECT id, name, parent_id
    FROM categories
    WHERE id = 5
    UNION ALL
    SELECT c.id, c.name, c.parent_id
    FROM categories c
    INNER JOIN ancestors a ON c.id = a.parent_id
)
SELECT * FROM ancestors;

2.2 路径枚举模型的查询

查询子树:

SELECT * FROM categories WHERE path LIKE '1/%';

查询祖先节点:

SELECT * FROM categories WHERE id IN (1, 2, 3);

2.3 嵌套集模型的查询

查询子树:

SELECT * FROM categories WHERE lft BETWEEN 2 AND 11;

查询祖先节点:

SELECT * FROM categories WHERE lft < 2 AND rgt > 11;

2.4 闭包表模型的查询

查询子树:

SELECT c.*
FROM categories c
JOIN category_closure cc ON c.id = cc.descendant
WHERE cc.ancestor = 1;

查询祖先节点:

SELECT c.*
FROM categories c
JOIN category_closure cc ON c.id = cc.ancestor
WHERE cc.descendant = 5;

3. 性能优化策略

在实际应用中,树形结构的查询性能可能会成为瓶颈。以下是一些常见的性能优化策略:

3.1 使用索引

在邻接表模型中,为parent_id字段创建索引可以加快递归查询的速度。

CREATE INDEX idx_parent_id ON categories(parent_id);

在路径枚举模型中,为path字段创建索引可以加快字符串匹配查询的速度。

CREATE INDEX idx_path ON categories(path);

在嵌套集模型中,为lftrgt字段创建索引可以加快范围查询的速度。

CREATE INDEX idx_lft_rgt ON categories(lft, rgt);

在闭包表模型中,为ancestordescendant字段创建索引可以加快JOIN操作的速度。

CREATE INDEX idx_ancestor_descendant ON category_closure(ancestor, descendant);

3.2 限制递归深度

在邻接表模型中,递归查询的深度可能会影响性能。可以通过限制递归深度来减少查询时间。

WITH RECURSIVE subcategories AS (
    SELECT id, name, parent_id, 1 AS depth
    FROM categories
    WHERE id = 1
    UNION ALL
    SELECT c.id, c.name, c.parent_id, s.depth + 1
    FROM categories c
    INNER JOIN subcategories s ON c.parent_id = s.id
    WHERE s.depth < 5
)
SELECT * FROM subcategories;

3.3 使用缓存

对于不经常变化的树形结构,可以将查询结果缓存起来,减少数据库查询次数。可以使用Redis等缓存系统来实现。

3.4 分区表

对于非常大的树形结构,可以考虑使用分区表来分散数据存储,提高查询性能。

CREATE TABLE categories (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    parent_id INT,
    FOREIGN KEY (parent_id) REFERENCES categories(id)
) PARTITION BY HASH(id) PARTITIONS 10;

4. 实例分析

4.1 场景描述

假设我们有一个电商网站,商品分类是一个树形结构。我们需要存储商品分类信息,并支持以下操作: - 查询某个分类的所有子分类。 - 查询某个分类的所有祖先分类。 - 插入新的分类。 - 删除某个分类。

4.2 存储方式选择

考虑到商品分类的深度不会太大,且需要频繁查询子分类和祖先分类,我们选择使用闭包表模型来存储树形结构。

4.3 表结构设计

CREATE TABLE categories (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL
);

CREATE TABLE category_closure (
    ancestor INT NOT NULL,
    descendant INT NOT NULL,
    depth INT NOT NULL,
    PRIMARY KEY (ancestor, descendant),
    FOREIGN KEY (ancestor) REFERENCES categories(id),
    FOREIGN KEY (descendant) REFERENCES categories(id)
);

4.4 数据插入

插入根分类:

INSERT INTO categories (name) VALUES ('电子产品');
SET @root_id = LAST_INSERT_ID();
INSERT INTO category_closure (ancestor, descendant, depth) VALUES (@root_id, @root_id, 0);

插入子分类:

INSERT INTO categories (name) VALUES ('手机');
SET @phone_id = LAST_INSERT_ID();
INSERT INTO category_closure (ancestor, descendant, depth)
SELECT ancestor, @phone_id, depth + 1
FROM category_closure
WHERE descendant = @root_id
UNION ALL
SELECT @phone_id, @phone_id, 0;

4.5 查询操作

查询某个分类的所有子分类:

SELECT c.*
FROM categories c
JOIN category_closure cc ON c.id = cc.descendant
WHERE cc.ancestor = 1;

查询某个分类的所有祖先分类:

SELECT c.*
FROM categories c
JOIN category_closure cc ON c.id = cc.ancestor
WHERE cc.descendant = 2;

4.6 删除操作

删除某个分类:

DELETE FROM categories WHERE id = 2;
DELETE FROM category_closure WHERE descendant = 2;

4.7 性能优化

使用索引:

CREATE INDEX idx_ancestor_descendant ON category_closure(ancestor, descendant);

限制递归深度:

在闭包表模型中,递归深度已经通过depth字段控制,无需额外限制。

使用缓存:

可以将查询结果缓存到Redis中,减少数据库查询次数。

5. 总结

MySQL中树形结构的存储和查询是一个复杂但重要的话题。通过合理选择存储方式、优化查询语句和使用索引等策略,可以显著提高树形结构的查询性能。本文介绍了四种常见的树形结构存储方式,并通过实例分析了闭包表模型的应用。希望本文能帮助读者更好地理解和应用MySQL中的树形结构存储与查询。

推荐阅读:
  1. Mysql如何通过Adjacency List存储树形结构
  2. 怎么使用SpringBoot+MyBatisPlus+MySQL8实现树形结构查询

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

mysql

上一篇:victoriaMetrics库布隆过滤器初始化及使用的方法

下一篇:mysql的单列多值存储实例分析

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》