【问题标题】:Hierarchical SQL data (Recursive CTE vs HierarchyID vs closure table)分层 SQL 数据(递归 CTE vs HierarchyID vs 闭包表)
【发布时间】:2013-06-22 13:37:39
【问题描述】:

我在 SQL Server 数据库中使用了一组分层数据。数据以 guid 作为主键存储,parentGuid 作为指向对象直接父对象的外键存储。我最常通过 WebApi 项目中的实体框架访问数据。为了使情况更复杂一点,我还需要基于此层次结构管理权限,以便应用于父级的权限适用于其所有后代。我的问题是这样的:

我已经搜索了所有内容,但无法确定哪种方法最适合处理这种情况。我知道我有以下选择。

  1. 我可以创建Recursive CTEs,通用表表达式,(又名RCTE)来处理分层数据。这似乎是正常访问最简单的方法,但我担心在用于确定子对象的权限级别时它可能会很慢。
  2. 我可以在表中创建一个hierarchyId 数据类型字段,并使用SQL Server 提供的函数,如GetAncestor()IsDescendantOf() 等。这似乎会使查询变得相当容易,但似乎需要一个相当复杂的插入/更新触发器,通过插入和移动来保持 hierarchyId 字段正确
  3. 我可以创建一个closure table,它将所有关系存储在表中。我想象它是这样的:父列和子列,每个父->子关系都将被表示。 (即 1->2 2->3 将在数据库中表示为 1-2、1-3、2-3)。缺点是这需要插入、更新和删除触发器,尽管它们相当简单,而且这种方法会生成大量记录。

我已经尝试过搜索,但在这三种方法之间找不到任何建议。

PS 我也愿意为这个问题提供任何替代解决方案

【问题讨论】:

  • 请用您正在使用的 SQL Server 版本标记您的问题。您的查询倾向于从孩子到父母,还是相反?一个 RCTE 沿着单个孩子的父链接走上树应该不会太糟糕。对所有孩子来说,走另一条路会变得很慢。
  • 我现在无法检查版本,但稍后会。我认为它要么是 2008 年,要么是更新的。我可能会更频繁地得到父母的孩子而不是得到孩子的父母
  • 我无法添加另一个标签,但它是 SQL Server 2008 r2。

标签: sql-server common-table-expression recursive-query hierarchyid transitive-closure-table


【解决方案1】:

我已经使用了所有三种方法。这主要是一个品味问题。

我同意表中具有父子关系的层次结构是最简单的。移动子树很简单,并且很容易使用 CTE 对递归访问进行编码。只有当您拥有非常大的树结构并且您经常访问分层数据时,性能才会成为问题。在大多数情况下,如果表上有正确的索引,递归 CTE 会非常快。

闭包表更像是对上述内容的补充。找到给定节点的所有后代非常快,您不需要 CTE,只需要一个额外的连接,所以很甜蜜。是的,记录的数量激增,但我认为它不超过 N-1 倍深度为 N 的树的节点数(例如深度为 5 的三叉树需要 1 + 3 + 9 + 27 + 81 = 仅存储父子关系时的 121 个连接,而闭包表的 1 + 3 + (9 * 2) + (27 * 3) + (81 * 4) = 427)。此外,闭包表记录非常窄(最少只有 2 个整数),几乎不占用空间。当新记录插入层次结构时,生成要插入闭包表的记录列表需要一点点开销。

我个人喜欢 HierarchyId,因为它确实结合了上述两个优点,即紧凑的存储和闪电般的快速访问。设置好后,查询起来很容易,而且占用的空间很小。正如您所提到的,移动子树有点棘手,但它是易于管理的。无论如何,您真正在层次结构中移动子树的频率是多少?您可以找到一些链接,这些链接会建议一些方法,例如:

http://sqlblogcasts.com/blogs/simons/archive/2008/03/31/SQL-Server-2008---HierarchyId---How-do-you-move-nodes-subtrees-around.aspx

我发现 hierarchyId 的主要缺点是学习曲线。如何使用它不像其他两种方法那样明显。我曾与一些非常聪明的 SQL 开发人员一起工作,他们经常会被它绊倒,所以你最终会遇到一两个常驻专家,他们必须回答其他人的问题。

【讨论】:

  • 我在最初涉足 hierarchyId 时遇到的两个缺点是,首先,在插入/更新触发器中处理批量插入/更新,其次,通过实体框架在 C# 中使用 hierarchyId 表。您对处理其中任何一个有任何建议或信息吗?此外,这个答案非常有帮助,但我会稍等片刻,然后再选择它以鼓励其他可能有有用信息的人。
  • 尝试在 Analysis Services 中使用这些类型的关系时遇到另一个缺点,无论选择何种方法来表示它们。 Analysis Services 不支持自联接、循环和hierarchyid,这意味着您最终不得不执行以下两种解决方法之一; (1) 创建展平视图来表示以这种方式存储的维度,或者 (2) 使用 SSIS 将维展平为 BI 数据库(星型或雪花模式)。每当将新项目添加到层次结构时,这两种解决方法都需要维护。
猜你喜欢
  • 1970-01-01
  • 2014-06-04
  • 2012-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-09
  • 2019-10-09
  • 2014-10-27
相关资源
最近更新 更多