【问题标题】:Efficient persistable recursive data structure高效的可持久递归数据结构
【发布时间】:2011-07-01 03:04:06
【问题描述】:

递归数据结构的常用方法是在每个对象中都有一个父指针。我的问题是通常的实现无法在一次操作中回答以下问题;相反,我需要多次查询我的数据库。有没有一种解决方案可以在单个查询中为我提供结果?

  • 获取一个节点的所有子节点的列表

  • 查找所有父节点(== 到根节点的最短路径)

注意:我在规划阶段,所以我还没有局限于某个数据库。

【问题讨论】:

  • “所有孩子”是否包括孩子的孩子?
  • @bdonlan:是的,包括每一片叶子。

标签: database data-structures recursion recursive-datastructures


【解决方案1】:

如果“所有子节点”仅表示直接子节点,则只需在每个节点上放置一个子节点列表以及指向父节点的指针。请注意,这会使将节点移动到另一个父节点的成本更高,因为所有(大)子节点也必须更新。

如果“所有孩子”真的意味着所有个孩子,一种选择是构建每个父母的ID字符串,并将其添加为索引列。例如,如果您有A,有子B,有孙C,那么您将在C 中有一个值为A/B/C 的列。现在要查找A 的所有孩子,您只需对"A/%" 进行LIKE 查询即可。但是,当您需要更改具有子节点的父节点时,这会很昂贵。

如果您需要能够快速更换父母,我认为您需要将父母信息作为链接列表进行维护。但是,您可以使用存储过程来执行此查询操作,只需一次数据库往返。

【讨论】:

  • +1 我的树结构非常静态(现实世界中的位置),所以我不需要移动操作。我经常需要查询 B/* 但我可以通过从项目中查找父路径来提高效率(所以我不需要like '%/B/%' 但可以使用更高效的like '/A/B/%'
  • 此建议或多或少符合 SQL Server 2008 HierarchyId 数据类型的工作方式:msdn.microsoft.com/en-us/library/bb677290.aspx
【解决方案2】:

至少Oracle可以做到hierarchical queries。考虑 db 用户角色的示例:

CREATE TABLE my_dba_role_privs(
   grantee        VARCHAR2(30),
   granted_role   VARCHAR2(30)
);   

-- assigning roles to roles
INSERT INTO my_dba_role_privs( grantee, granted_role ) VALUES('CLIENT', 'SELECT_ORDERS');
INSERT INTO my_dba_role_privs( grantee, granted_role ) VALUES('COMMERCIAL_DEP', 'CREATE_ORDERS');
INSERT INTO my_dba_role_privs( grantee, granted_role ) VALUES('COMMERCIAL_DEP', 'CLIENT');

-- assigning roles to users
INSERT INTO my_dba_role_privs( grantee, granted_role ) VALUES('CL_MATT', 'CLIENT');
INSERT INTO my_dba_role_privs( grantee, granted_role ) VALUES('CL_JOHN', 'CLIENT');
INSERT INTO my_dba_role_privs( grantee, granted_role ) VALUES('CM_MARY', 'COMMERCIAL_DEP');

现在选择用户“CM_MARY”的所有角色:

SELECT DISTINCT GRANTED_ROLE role_name
  FROM my_dba_role_privs
 START WITH GRANTEE = 'CM_MARY'
       CONNECT BY GRANTEE = PRIOR GRANTED_ROLE;   

结果:
COMMERCIAL_DEP
CREATE_ORDERS
客户
SELECT_ORDERS

选择拥有角色“客户”的所有角色和用户

SELECT GRANTEE role_name
  FROM my_dba_role_privs
 START WITH GRANTED_ROLE = 'CLIENT'
       CONNECT BY GRANTED_ROLE = PRIOR GRANTEE;   

结果:
CL_JOHN
CL_MATT
COMMERCIAL_DEP
CM_MARY

更新:
既然你提到了,树将是相当静态的,尝试Joe Celko's Trees 可能会很有趣(大约 180 行要阅读)。 它根本不需要自我加入!所以,我希望它的执行速度比 CONNECT BY 快。虽然我刚刚在 30 分钟前读到它,但不知道它在现实世界中的效果如何

更新 2:“嵌套集模型”与 MySQL:Managing Hierarchical Data in MySQL 这与上面 Joe Celko 的树相同,但有更多示例和解释。

【讨论】:

  • Oracle 是否有效地缓存/索引这些数据?或者这更像是把递归查询从应用代码移到 DB 层?
  • @Aaron:我还没有在官方文档或 AskTom 上找到明确的答案。从off site 看来,Oracle 似乎做了所有递归查询,但我很确定 DB 能够做一些技巧来提高性能。关于我自己的经验,我公司的 AFAIK 仅在一个地方使用 - 确定所有用户的角色(如我的帖子中所示)。在我们的测试数据库中,dba_role_privs 中有 3000 行,查询在 70 毫秒内执行,这不是很快,但对我们来说很好
  • @Aaron:另外,我用非常有趣的链接更新了我的答案
  • Celko Trees 看起来很有前途。起初,因为左右管理的成本而犹豫不决,但由于我很少更改数据结构,那应该没问题。
  • @AaronDigulla,你试过 Celko 树吗?您能分享一下他们在生产中的表现(性能、实现、支持问题)吗?
猜你喜欢
  • 1970-01-01
  • 2011-09-02
  • 1970-01-01
  • 2013-04-17
  • 1970-01-01
  • 1970-01-01
  • 2011-03-07
  • 1970-01-01
相关资源
最近更新 更多