【问题标题】:Adjacent List Model Tree, preventing loop相邻列表模型树,防止循环
【发布时间】:2016-04-19 19:57:38
【问题描述】:

示例表:

CREATE TABLE adj_list_model (
    id INT NOT NULL AUTO INCREMENT,
    parent_id INT,
    my_string varchar(255),//some random information
    PRIMARY KEY (id)
)

我正在创建的树将在同一个表中有多个“root”用户(当 parent_id = NULL 时)。这些“root”用户可能在某些时候 从某个“叶”用户(没有任何人的用户)那里获取 parent_id。我的疑问是如何确保我不创造 类似于以下的“循环”:

示例树设计:

  • 一个
    • b
    • c
      • d
        • e
        • f
          • g

如果用户“a”获得用户“g”作为他的父母,那么创建的循环将是:

a -> c -> d -> f -> g -> a -> c... and so on forever

问题:当用户“a”想要转到树中的用户“g”下时,检查用户“g”是否在用户“a”下的好方法是什么? (以便在这些特定情况下可以防止该操作)

需要考虑的要点: 两棵树合并为一棵树会经常发生。如果树中的级别数假设为 80,则进行检查以防止循环所需的时间可能相当可观,这就是我寻找有效方法的原因。


已编辑: 我目前的选择(尽管我持怀疑态度)是:

  1. 创建一个额外的列,显示表中每个用户的当前“root”用户。在这种情况下,每次“root”用户获得父用户时,他下面的每个人都必须更新为新的“root”用户,而我担心的是这会给服务器带来多大的压力,特别是如果有很多用户,如果“root”用户获得父母的频率很高。

  2. 在给他父母之前检查“root”用户路径。如果在上述情况下,用户“g”通过逐个遍历 g 以上的每个用户(查看他们的父级,一遍又一遍直到到达根目录)来检查他的路径,并发现根目录是用户“a” ,然后是的,可以阻止该操作,尽管我不确定这会对服务器造成多大的压力。如果有人有想法,请告诉我!

【问题讨论】:

  • 您可能需要递归查询。我要做的只是添加一个列来存储这个元素的根。当您更改结构中的某些内容时,您还必须更新这些值,但这可以在没有递归的情况下完成。
  • @flowit 所以我之前考虑过这样做,但正如你所说,每次“根”获得父级时,该根下的每个人都必须更新,这在服务器,如果表有很多用户,并且在这些用户中,“root”用户获取父母的行为很频繁。还有其他可能性吗?

标签: sql tree circular-reference adjacency-list-model


【解决方案1】:

对于带有附加 root_id 列的选项,在 MySql 语法中:

CREATE PROCEDURE change_root() 
BEGIN

  # this is the leaf node id, which will be the new parent of a root user
  SET @new_parent = x;
  # this is the old root user id, which will be the new child of the former leaf node
  SET @old_root = y;
  # get the leaf's root
  SET @new_root = SELECT root_id FROM adj_list_model WHERE id=x;

  # updating the dataset is possible as long as the leaf is not a child of the root user
  IF @new_root <> y THEN

    # link the former leaf to its new child
    UPDATE adj_list_model SET parent_id=x WHERE id=y;

    # @old_root is no longer a root, so update all occurences to the new root
    UPDATE adj_list_model SET root_id=@new_root WHERE root_id=@old_root;

  END IF;

END;

这实际上并不复杂,而且比递归解决方案快得多。但最终这取决于您的工作量和需求。

【讨论】:

  • 感谢您的回答!在您的示例中是否会为 root_id 编制索引?如果它没有被索引,考虑到它会遍历每一个条目,UPDATE adj_list_model SET root_id=@new_root WHERE root_id=@old_root; 不会花费很长时间来处理一个大表吗?
  • 正如我所说,取决于您的工作量。这些更新多久发生一次?也许这种情况很少发生,以至于多花几毫秒的时间来保持 root_id 的索引是不值得的。试试看!
  • 因此,例如,如果数据库必须更新 80 个不同的用户,您会说所有更新都将在 1 秒内完成吗?更重要的是,您猜需要更新多少用户才能在 1 秒内完成代码?
  • 我怎么知道?我不知道你的硬件,我不知道你的 DBMS,我对你的用户一无所知。试试看。您还可以阅读分析和调优,但只有在您发现系统太慢之后。
猜你喜欢
  • 1970-01-01
  • 2018-07-31
  • 1970-01-01
  • 2021-11-03
  • 2014-09-10
  • 2021-03-12
  • 2018-03-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多