21

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

我已经搜遍了,无法决定哪种方法最适合处理这种情况。我知道我有以下选择。

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

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

PS我也对这个问题的任何替代解决方案持开放态度

4

1 回答 1

15

这三种方法我都用过。主要是口味问题。

我同意表中具有父子关系的层次结构是最简单的。移动子树很简单,并且很容易使用 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 开发人员一起工作,他们经常会被它缠住,所以你最终会遇到一两个常驻专家,他们必须回答其他人的问题。

于 2013-06-25T21:44:15.597 回答