我正在开发一个小博客软件,我想在帖子上附上标签。每个帖子可以有0到无限的标签,我想知道是否可以在不加入表格的情况下做到这一点?
由于标签的数量不受限制,我不能只创建n个字段(Tag1到TagN),因此另一种方法(显然是StackOverflow采用的方法)是使用一个大文本字段和分隔符,即“ < Tag1中><与Tag2>< TAG3>”
问题在于:如果我想显示带有标签的所有帖子,我将不得不使用“赞'%< Tag2>%'”语句,那些AFAIK可以不使用任何索引,需要一个完整的表扫描。
有没有合适的方法来解决这个问题?
注意:我知道单独的Tag-Link-Table提供了好处,我不应该在没有测量等的情况下担心性能。我对设计系统的不同方式更感兴趣。
答案 0 :(得分:6)
想要在没有加入的情况下这样做会让我觉得不成熟。如果经常访问此表,则其页面很可能在内存中,并且您不会从中读取I / O代价,并且可能会缓存访问它的查询计划。
答案 1 :(得分:3)
单独的标签表真的是唯一的方法。这是允许无限数量标签的唯一方法。
答案 2 :(得分:2)
这听起来像是非规范化的练习。所有真正需要的是一个表,它可以自然地支持你碰巧遇到的任何查询,通过重复你原本必须加入另一个表来满足的任何信息。一个标准化的数据库,你可能会看到类似的东西:
Posts:
PostID | PostTitle | PostBody | PostAuthor
--------+--------------+-------------------+-------------
1146044 | Join-Free... | I'm working on... | Michael Stum
Tags:
TagID | TagName
------+-------------
1 | Archetecture
PostTags:
PostID | TagID
--------+------
1146044 | 1
然后,您可以添加列以优化查询。如果是我,我可能只留下Posts
和Tags
表,并将额外信息添加到PostTags
联接表中。当然我添加的内容可能取决于我打算运行的查询,但可能我至少添加了Posts.PostTitle
,Posts.PostAuthor
和Tags.TagName
,所以我只需要运行显示博客帖子的两个查询,
SELECT * FROM `Posts` WHERE `Posts`.`PostID` = $1
SELECT * FROM `PostTags` WHERE `PostTags`.`PostID` = $1
总结给定标签的所有帖子需要更少,
SELECT * FROM `PostTags` WHERE `PostTags`.`TagName` = $1
显然,非规范化的缺点是它意味着你必须做更多的工作来使非规范化表保持最新。处理此问题的一种典型方法是在代码中进行一些健全性检查,通过将非正规化查询与其碰巧可用的其他信息进行比较来检测非规范化查询何时不同步。通过将PostTags
结果集中的帖子标题与Posts
结果中的标题进行比较,可以在上面的示例中进行此类检查。这不会导致额外的查询。如果存在不匹配,程序可以通知管理员,即记录不一致或发送电子邮件。
修复它很容易(但在服务器工作负载方面成本很高),抛弃额外的列并从规范化表中重新生成它们。显然,在找到数据库不同步的原因之前,不应该这样做。
答案 3 :(得分:0)
如果您使用的是SQL Server,则可以使用单个文本字段(varchar(max)似乎合适)和全文索引。然后只需对您要查找的标记进行全文搜索。