8

我有一个 PHP Web 应用程序,它使用 MySQL 数据库进行对象标记,其中我使用了接受的标记结构作为这个 SO question的答案。

我想实现一个标签层次结构,其中每个标签都可以有一个唯一的父标签。然后,对父标签 T 的搜索将匹配 T 的所有后代(即 T、父标签为 T(T 的子代)、T 的孙子代等)。

最简单的方法似乎是在标签表中添加一个 ParentID 字段,该字段包含标签的父标签的 ID,或者如果标签没有父标签,则包含一些幻数。然而,搜索后代需要对数据库进行重复的完整搜索以找到每个“世代”中的标签,我想避免这种情况。

一种(可能)更快但标准化程度较低的方法是拥有一个包含每个标签的所有子代,甚至每个标签的所有后代的表。然而,这会带来数据库中数据不一致的风险(例如,标签是多个父级的子级)。

有没有一种好方法可以让查询快速找到后代,同时保持数据尽可能规范化?

4

5 回答 5

9

我使用两列实现了它。我在这里简化了一点,因为我必须将标签名称保存在单独的字段/表中,因为我必须针对不同的语言对其进行本地化:

  • 标签
  • 小路

例如,查看这些行:

tag            path
---            ----
database       database/
mysql          database/mysql/
mysql4         database/mysql/mysql4/
mysql4-1       database/mysql/mysql4-1/
oracle         database/oracle/
sqlserver      database/sqlserver/
sqlserver2005  database/sqlserver/sqlserver2005/
sqlserver2005  database/sqlserver/sqlserver2008/

等等

使用like路径字段上的运算符,您可以轻松获取所有需要的标记行:

SELECT * FROM tags WHERE path LIKE 'database/%'

有一些实现细节,例如当您在层次结构中移动节点时,您也必须更改所有子节点等,但这并不难。

还要确保路径的长度足够长 - 在我的情况下,我没有使用路径的标记名称,而是使用另一个字段来确保我不会得到太长的路径。

于 2008-11-02T16:15:00.350 回答
2

Ali 的答案有一个链接到Joe Celko 的 Trees and Hierarchies in SQL for Smarties,这证实了我的怀疑 - 没有一个简单的数据库结构可以提供世界上最好的。最适合我的目的似乎是这本书中详述的“频繁插入树”,它类似于阿里链接的“嵌套集模型”,但具有非连续索引。这允许 O(1) 插入(a la非结构化 BASIC 行编号),并在需要时偶尔进行索引重组。

于 2008-11-02T18:24:26.983 回答
1

这里有几种方法

于 2008-11-02T16:19:16.723 回答
1

您可以构建 Kimball 所说的 Hierarchy Helper Table。

假设您的层次结构如下所示: A -> B | B -> C | C -> D

您会将记录插入到如下所示的表中

ParentID, ChildID, Depth, Highest Flag, Lowest Flag
A, A, 0, Y, N
A, B, 1, N, N
A, C, 2, N, N
A, D, 3, N, Y
B, B, 0, N, N
B, C, 1, N, N
B, D, 2, N, Y
C, C, 0, N, N
C, D, 1, N, Y
D, D, 0. N, Y

我想我是正确的....无论如何。关键是你仍然正确地存储你的层次结构,你只是从你正确的表中构建这个表。这个表查询就像一个女妖。假设您想知道 B 以下的所有第一级是什么。

WHERE parentID = 'B' and Depth = 1
于 2008-11-03T17:45:26.953 回答
0

我会使用某种数组来存储子标签,这应该比在自身上加入表格要快得多(特别是如果你有大量标签)。我看了一下,我不知道 mysql 是否具有本机数组数据类型,但您可以通过使用文本列并在其中存储序列化数组来模拟这一点。如果您想进一步加快速度,您应该能够在该列上放置一个文本搜索索引以找出哪些标签是相关的。

[编辑] 在阅读了 Ali 的文章后,我进行了更多的搜索,并发现了这篇关于在 postgres 中实现层次结构的方法的演示文稿。可能仍然有助于解释目的。

于 2008-11-02T17:46:59.820 回答