[英]Implementing a hierarchical data structure in a database
我知道有两种方法:邻接列表和嵌套树。 据说由于大量查询,邻接列表在遍历上使用会很慢。 但我不知道这方面的任何实际数字。 我正在制作的网站将有200页。 遍历生成(例如)站点地图需要花费超过0.3秒的时间吗?
使用LAMP堆栈在MySQL(innoDB)上运行。
如果可能的话,我更愿意实现邻接,因为设计更简单。
谢谢。
除了你提到的两个选项之外,还有更多的选择。 有:
请参阅我的回答“ 什么是将平台解析成树的最有效/优雅的方法? ”
或者几本书:
MySQL中管理分层数据的文章详细介绍了这一点。
我建议使用“嵌套集”技术,因为它允许您在一个查询中获取整个树(及其子节点)。 基本上读取是便宜的,但写入是昂贵的,因为整个树必须重新平衡。 但是如果你有99%的读数,那么它是完全合理的。
解析邻接列表的天真方法需要大量查询,而对于大型列表,可能需要花费大量时间来构建内存。 作为参考,我所指的天真方法可以概括为:选择没有父项的所有项目,然后为每个项目递归地获取它的子项。 此方法需要n + 1个数据库查询。
我使用以下方法构建一个带有1个查询的邻接列表。 从数据库中选择所有项目。 将所有项目转移到由其键索引的数组中。 遍历数组并将父对象的引用分配给每个子对象。 第二次遍历数组并删除仅留下根级对象的所有子对象。
既然你提到了LAMP堆栈,那么PHP代码大致如下:
<?php
// Assumes $src is the array if items from the database.
$tmp = array();
// Traverse the array and index it by id, ensuing each item has an empty array of children.
foreach ($src as $item) {
$item['children'] = array();
$tmp[$item['id']] = $item;
}
// Now traverse the array a second time and link children to their parents.
foreach ($tmp as $id => $item) {
if ($item['parent_id'] != 0 || $item['parent_id'] !== NULL) {
$tmp[$item['parent_id']]['children'][$id] = &$tmp[$id];
}
}
// Finally create an array with just root level items.
$tree = array();
foreach ($tmp as $id => $item) {
if ($item['parent_id'] == 0 || $item['parent_id'] === NULL) {
$tree[$id] = $item;
}
}
// $tree now contains our adjacency list in tree form.
?>
请注意,此代码旨在说明从单个数据库查询构建邻接列表的技术。 它可能可以针对更少的内存消耗等进行优化。它还没有经过测试。
吉姆
我认为另一种方法称为“嵌套集”,而不是“嵌套树”。
无论如何,站点地图的一个好处是你可能知道它的最大深度。 我认为邻接模型的问题是相应的SQL一次只能在一个层面上工作,所以如果你有'n'个级别,那么你需要一个'n'个SQL语句的循环...但我认为(我'我不确定)如果您事先知道最大'n',那么您可以编写相应的固定数量级别的SQL。
0.3秒听起来像很长一段时间才能看到200页,所以这可能还行。
站点地图也不经常更新; 因此,即使从SQL检索确实需要很长时间,您也可以将检索/计算的树缓存在RAM中。
或者,不要担心构建树的SQL,您可以尽可能简单地存储它(作为邻接列表),从数据库中将其作为一组简单的行检索,并在RAM中构建树(使用循环)您的高级编程语言)而不是使用SQL中的循环来使用SQL语句构建树。
为了完整性:Oracle具有START_WITH
和CONNECT_BY
运算符:请参阅此分层查询文档。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.