SQL中的分层标记

时间:2008-11-02 15:57:04

标签: sql mysql database tags normalizing

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

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

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

一种(可能)更快但更少规范化的方法是拥有一个包含每个标记的所有子项的表,甚至每个标记的所有后代。然而,这会冒数据库中数据不一致的风险(例如,标签是多个父母的子项)。

是否有一种很好的方法可以使查询快速查找后代,同时尽可能保持数据的标准化?

5 个答案:

答案 0 :(得分:8)

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

  • 标签
  • 路径

例如,查看这些行:

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/%'

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

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

答案 1 :(得分:2)

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

答案 2 :(得分:1)

答案 3 :(得分:1)

您可以构建Kimball称为层次结构助手表的内容。

假设您的层次结构如下所示: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

我认为我有正确的......反正。关键是你仍然正确地存储你的层次结构,你只需从正确的表中构建这个表。这个表像Banshee一样查询。假设您想知道B下面的所有第一级是什么。

WHERE parentID = 'B' and Depth = 1

答案 4 :(得分:0)

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

[编辑] 阅读了阿里的文章之后,我又做了一些狩猎,并发现this介绍了一系列在postgres中实现层次结构的方法。可能仍然有助于解释目的。