这是:
mysql-是否可以在层次结构中获得所有子项目?

我有一个任意深度 邻接列表模型 桌子(我正处于我 能够 将其转换为一个 嵌套集模型.

我阅读了有关如何使用嵌套集模型的MySQL数据,尽管它似乎变得越来越复杂且非常复杂,可以执行诸如插入,更新和删除之类的基本功能。

另一个博客显示了如何使用邻接列表模型使用触发系统来保留将每个对象与祖先联系起来的祖先表。


现在,我需要能够返回给定节点的所有孩子的列表,以更改或删除它们。这种层次结构一旦创建就不会一直在改变,但是会有大量的层次结构。

我看到的三种方法是:

  1. 创建了一个存储过程 这将进行递归查询,以返回所有孩子。

  2. 转换为嵌套集模型 这将需要进入复杂性,并可能创建一个存储过程以在其中添加,编辑和删除。

  3. 创建祖先表 上面在插入/删除触发器上描述以处理所有数据。

如果我没有探索其他方法,请告诉我,我将更新此列表。

有帮助吗?

解决方案

quassnoi 是否在嵌套集模型和邻接列表模型上进行了一些性能测试,并在其博客文章中记录了结果和建议 邻接列表与嵌套集:MySQL. 。执行摘要是:

  • 嵌套集的速度更快,用于获取所有子节点或所有父节点。
  • 如果您经常需要更新表,嵌套集是一个坏主意。

这是他的文章的结论:

在MySQL中,如果层次结构的更新很少,则应优选嵌套集模型,并且在更新的时间内锁定桌子是负担得起的(可以在长桌上花费几分钟)。

这意味着使用Myisam存储引擎创建表格,创建如上所述的几何类型的边界框,用空间索引索引并持续表格。

如果表格的更新是频繁的,或者不承担长时间锁定表的长时间,则应使用邻接列表模型来存储层次结构数据。

这需要创建一个函数来查询表。

本文的其余部分显示了如何定义表,实现查询并提供性能测量值。空间索引的使用是一个聪明的想法,可以提高可能是新的嵌套集模型的性能。


如果您还考虑没有MySQL的方法,那么您可能想看看 Postgresql 这是另一个免费的开源数据库。 PostgreSQL支持递归查询的形式 递归公共表格表达 这使得与MySQL更容易查询继承人数数据,并且还能提供更好的性能。 Quassnoi还写了一篇文章 邻接列表与嵌套集:PostgreSQL 这显示了细节。

当我们谈论查看其他方法时,Oracle的数据库也值得一提。 Oracle还具有自定义扩展名 CONNECT BY 这使查询继承制数据非常容易快速。 Quassnoi的文章 邻接列表与嵌套集:Oracle 再次介绍性能细节。在这种情况下,您需要让所有孩子的查询非常简单:

SELECT *
FROM yourtable
START WITH id = 42
CONNECT BY parent = PRIOR id

其他提示

我总是会和 嵌套集 出于剪切简单和说服力。我总是建议 本文. 。它显示了使用此类Hierachrchical数据所需的查询。我在这里看到的唯一缺点是,当hierachry达到一定的复杂性时,插入/更新新记录的插入/更新可能会慢,但是阅读速度比我看到的许多其他解决方案要快。

只是为您提供以上文章的示例:

SELECT t1.name AS lev1, t2.name as lev2, t3.name as lev3, t4.name as lev4
FROM category AS t1
LEFT JOIN category AS t2 ON t2.parent = t1.category_id
LEFT JOIN category AS t3 ON t3.parent = t2.category_id
LEFT JOIN category AS t4 ON t4.parent = t3.category_id
WHERE t1.name = 'ELECTRONICS';

+-------------+----------------------+--------------+-------+
| lev1        | lev2                 | lev3         | lev4  |
+-------------+----------------------+--------------+-------+
| ELECTRONICS | TELEVISIONS          | TUBE         | NULL  |
| ELECTRONICS | TELEVISIONS          | LCD          | NULL  |
| ELECTRONICS | TELEVISIONS          | PLASMA       | NULL  |
| ELECTRONICS | PORTABLE ELECTRONICS | MP3 PLAYERS  | FLASH |
| ELECTRONICS | PORTABLE ELECTRONICS | CD PLAYERS   | NULL  |
| ELECTRONICS | PORTABLE ELECTRONICS | 2 WAY RADIOS | NULL  |
+-------------+----------------------+--------------+-------+
6 rows in set (0.00 sec)

SQL明智,我认为它不会变得更漂亮,更简单;)

我不知道 存储过程 方式。但是,由于它涉及递归(就您而言),所以我不知道它是否会在层次结构中具有许多层次。我认为您可以尝试一下。

也许您应该考虑使用面向文档的数据库 mongodb. 。这可能会使您的生活更轻松。

在处理层次数据集时,我发现最好考虑一下缓存。这种方式处理此问题的主要好处之一是,它不需要将数据库脱颖而出,将数据库分为可能很难突变。

由于内存堆(memcache,redis等)查找速度比SQL快得多 id -> data 决议,我将使用它们来缓存每个节点的直接儿童ID列表。这样,您可以通过递归算法获得体面的性能,以构建任何节点的完整列表。

要添加/删除一个新节点,您只需要无效其'直接parent Cache O(1).

如果这还不够快,您可以将另一层缓存添加到每个节点上所有节点的所有孩子的列表中。为了使其使用一个可变的数据集,您应该记录每个节点的缓存性能(新鲜/缓存命中的比率),并为何时存储缓存设置公差级别。由于它是非重要数据,因此也可以存储在内存堆中。

如果您使用此更高级的缓存模型,则需要注意这些完整的儿童节点列表,需要在任何孩子更改时都需要无效 O(log n).

一旦您拥有孩子ID的列表,您可以使用SQL WHERE id IN( id1, id2, .... ) 语法查询您想要的内容。

我曾经不得不将复杂的层次结构任意深度存储在类似于SQL的数据库管理器中,这并不是真正完成任务,并且最终强迫凌乱而棘手地表明,数据定义,查询等。理解,更简单地维护和增强。所需的最复杂的查询本质上是从B中选择A。

因此,与其将逻辑和操作嵌入MySQL的限制内,不如考虑敲打代码来完成您想要的事情,而仅依靠MySQL才能获得最低级别的获取/puts。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top