2010-06-29 56 views
5

这是一个后续到:
MySQL - Is it possible to get all sub-items in a hierarchy?MySQL - 处理这种分层数据的最佳方法?

我有一个任意深度的邻接表模型表(我在我可以将其转换为嵌套集模型

我读了关于如何使用嵌套集模型的MySQL数据,虽然它似乎变得越来越复杂并且非常复杂,以至于无法完成插入,更新和删除等基本功能。

另一个博客展示了如何在邻接列表模型中使用触发器系统,以保存一个将每个对象与其祖先关联起来的祖先表。


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

的三种方法我看到的是:

  1. 创建存储过程时这将做到这一点返回所有孩子递归查询。

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

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

如果还有其他方法我不探索,请让我知道,我会更新此列表。

+1

*我将这个添加为评论而不是答案,因为这是我最近才看到的:我没有使用这种方法,但我还没有完全理解,但我认为你可能至少会发现它很有趣。[[用连续分数嵌套间隔树编码](http://arxiv.org/ftp/cs/papers/0402/0402051.pdf)(Vadim Tropashko)看起来很有趣,而且是对[与Farey分数的嵌套间隔](http://arxiv.org/html/cs/0401014)。和所有的方法一样,有利弊 - 这只是你可能想添加到你的列表中的东西。 – Mike 2010-07-04 10:55:47

+0

你有没有考虑过不使用关系数据库?我忍不住想像图形数据库这样的东西会更好。 – 2010-07-06 15:15:10

+0

从未听说过图形数据库?我也需要知道它在速度和优化方面的比较。这只是整个系统的一小部分,所以它必须与其余的部分并驾齐驱。 – 2010-07-06 19:33:53

回答

4

Quassnoi已对嵌套集模型和邻接列表模型运行了一些性能测试,并在其博客文章Adjacency list vs. nested sets: MySQL中记录了结果和建议。执行摘要如下:

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

以下是他的文章的结论:

在MySQL中,嵌套集合模型应该是首选,如果更新到hierarhical结构是罕见的,这是经济实惠锁定该表的时间的更新(在长桌上可能需要几分钟)。

这意味着使用MyISAM存储引擎创建表,创建如上所述的GEOMETRY类型的边界框,使用SPATIAL索引对其进行索引并在表中保留该级别。

如果对表的更新频繁或无法锁定更新所隐含的很长一段时间,则应使用邻接列表模型来存储分层数据。

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

本文其余部分将介绍如何定义表,实现查询并提供性能测量。空间索引的使用是一个聪明的想法,可以提高嵌套集合模型的性能,这对您而言可能是新的。


如果你还在考虑不MySQL的方式,那么你可能想看看PostgreSQL这是另一种免费的开源数据库。 PostgreSQL支持以recursive common table expressions的形式进行递归查询,这些查询比在MySQL中更容易查询叶面数据,并且还提供了更好的性能。 Quassnoi还写了一篇文章Adjacency list vs. nested sets: PostgreSQL,显示细节。我们在谈论其他方法时,Oracle的数据库也值得一提。 Oracle还有一个自定义扩展CONNECT BY,它可以非常简单快速地查询叶面数据。 Quassnoi的文章Adjacency list vs. nested sets: Oracle再次涵盖了性能细节。你需要让所有的孩子查询在这种情况下非常简单:

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

我总是会用嵌套剪切简单和快速。我总是建议this article。它显示了使用这种分层数据工作所需的查询。我在这里看到的唯一缺点是,当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明智的,我不认为它可以得到任何漂亮和更简单;)

我不知道到存储过程的方式。但因为它涉及递归(在你的情况下),我不知道它是否会在层次结构中的许多级别上快速。我假设你可以试试看。

+0

这是我用于嵌套集模型的文章。我遇到的问题是它会在您插入,更新或删除时锁定整个表。我不能那样做。您为邻接列表模型显示的另一种方法适用于已知深度。我有任意的深度。 – 2010-06-29 06:36:09

+0

我不认为应该有必要进行锁定。如果你使用InnoDB作为引擎,你应该保持安全。 – DrColossos 2010-06-29 07:09:19

+0

现在就是MyISAM--你知道一个很好的参考资料,可以说明差异/优点/缺点吗? – 2010-06-29 07:24:25

1

也许你应该考虑使用面向文档的数据库一样MongoDB。它可以让你的生活变得更容易。

+0

我不敢暗示这一点,但我完全同意。还要考虑像Tamino这样的面向对象数据库(http://www.softwareag.com/Corporate/products/wm/tamino/default.asp) – 2010-07-02 00:09:35

-1

我曾经不得不在一个类似于SQL的数据库管理器中存储一个复杂的分层任意深度物料清单系统,该系统并不真正完成任务,最终导致了混乱和棘手的索引,数据定义,查询等。从头开始重新启动后,使用数据库管理器为简单索引键上的记录读取和写入提供一个API,并在外部代码中执行所有实际输入/操作/报告,最终结果更快实施,更容易理解,更容易维护和提高。所需的最复杂的查询实质上是SELECT A FROM B.因此,不要将逻辑和操作嵌入到MySQL的限制之内,而是考虑敲出代码来执行您想要的操作,并且仅依靠MySQL来实现最低级别获取/看跌期权。

1

当处理分层数据集时,我发现最好先考虑缓存来处理它。这种以这种方式处理这个问题的主要好处之一就是它不需要将数据库解除规范化为可能难以改变的东西。

由于对于简单的id -> data分辨率,内存堆(memcache,redis等)查找比SQL快得多,所以我会使用它们来缓存每个节点的直接子项的ID列表。这样,您可以通过递归算法获得不错的性能,为任何节点构建完整列表。

要添加/删除新节点,您只需要使其“直接父缓存O(1)无效”。

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

如果你使用这个更高级的缓存模型,你将需要注意到这些完整的子节点列表将需要失效,当它的任何子节点被更改O(log n)

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

相关问题