【发布时间】:2016-05-25 14:41:59
【问题描述】:
我有一个存储在关系数据库中的层次结构,它以树形视图表示。 每个节点都有其属性的各种字段,并通过 ID 知道其父节点。 这是一个父子关系模型。
如果一个节点有一个子节点,则在节点名称前用 [+] 表示。通过单击 [+],您可以展开节点并查看子节点。 子节点本身有一个 [+],如果他们有子节点等等到最低级别。
一个简化的示例树视图如下所示:
[+] A Land
[+] A.1 Car
A.1.A Motor
A.1.B Wheels
[+] B Sea
B.1 Sailing ship
[+] B.2 Motorboat
B.2.A Motor
[+] C Air
[+] C.1 Plane
C.1.A Turbine
C.2.B Wheels
可以在各种节点属性上设置一个或多个过滤器,例如显示所有具有名为“Motor”的后代的节点。 树视图看起来像:
[+] A Land
[+] A.1 Car
A.1.A Motor
[+] B Sea
[+] B.2 Motorboat
B.2.A Motor
由于我的关卡数量和节点数量有限,这个结构可以满足我的需求(性能一般)。
现在我们要将树视图扩展到 n 级深度。
有嵌套集合模型,只要不过滤掉,性能就很好。这是因为据我们所知,嵌套集不支持过滤。我们还尝试了路径模型(SQL-Servers hierarchyid-datatype),但是如果您有很多级别,过滤会很慢。
我们的路径模型方法: 想象一下,您有 20 个级别,在 tbale PMTable 中的每个级别中有很多节点,其中有一个层次结构 ID 数据类型的列路径。然后你不想查询(初始化 TreeView)所有具有至少一个后代(必须不是直接后代,descandant 可以具有每个可能的级别)的顶级节点,这些节点适用于过滤器(例如:名称LIKE '%motor%' AND type = 3,其中名称和类型是同一路径模型表中的列)。我们还存储了节点的从零开始的级别以简化查询。
查询可能是:
SELECT id, name
FROM PMTable WHERE level = 0
AND Path IN
(
SELECT Path WHERE Path.GetAncestor(Path.GetLevel() - 1)
FROM PMTable
WHERE name LIKE '%motor%' AND type = 3
)
ORDER BY name
这个查询可能性能一般,但正如您所见,在顶级查询中您也有一个昂贵的子查询,它必须从表中查询符合条件的所有节点。
但是如果用户点击小 [+] 来展开一个顶级节点,您必须查询所有二级节点,将点击的节点作为祖先并且还匹配该过滤条件(包含任何级别的 descandants,即火柴)。如果一个节点本身符合过滤条件(类型 3 并且名称包括“电机”),那么您必须显示它的所有后代。
这些查询在我们的示例中表现不佳。
是否有任何其他模型您可以更喜欢或一些想法以获得更好的性能。
谢谢!
【问题讨论】:
-
您有一个示例说明为什么不能使用嵌套集模型进行过滤吗?实际上,在该模型中按后代过滤似乎非常简单。
-
据我所知,您可以轻松检查节点是否有后代,是的。但是我们必须检查一个节点是否有符合某些过滤条件的后代。只要嵌套集模型的 Left 和 Right 值提供有关是否包含 descandants 的反馈,并且如果我过滤掉一些行,它们就不会改变,就没有办法。我说的对吗?
-
您当然可以使用嵌套集和过滤。它实际上完全按照您用文字描述的那样工作:选择每个具有后代的节点(这意味着:某个节点的左/右在节点的左右之间)或它本身满足过滤条件:
select * from node where exists (select * from nodes as n where "filtercriteria for your nodes" and node.left <= n.left and node.right >= n.right) -
mysql 还是 sql-server?你已经用这两个标记了这个问题。
-
其实是 SQL-Server
标签: mysql sql sql-server treeview hierarchical-data