Sql server 标记的联接自由表结构

Sql server 标记的联接自由表结构,sql-server,database,database-design,architecture,Sql Server,Database,Database Design,Architecture,我正在开发一个小博客软件,我想把标签贴在帖子上。每个帖子可以有0到无限个标记,我想知道是否有可能不用连接表就可以做到这一点 由于标记的数量不受限制,我不能只创建n个字段(Tag1到TagN),因此另一种方法(显然是StackOverflow采用的方法)是使用一个大文本字段和一个分隔符,即“” 这里的问题是:如果我想用一个标记显示所有文章,我必须使用一个“Like“%”语句,而那些语句可能不使用任何索引,需要进行完整的表扫描 有没有合适的方法来解决这个问题 注意:我知道单独的标签链接表提供了好处,

我正在开发一个小博客软件,我想把标签贴在帖子上。每个帖子可以有0到无限个标记,我想知道是否有可能不用连接表就可以做到这一点

由于标记的数量不受限制,我不能只创建n个字段(Tag1到TagN),因此另一种方法(显然是StackOverflow采用的方法)是使用一个大文本字段和一个分隔符,即“”

这里的问题是:如果我想用一个标记显示所有文章,我必须使用一个“Like“%”语句,而那些语句可能不使用任何索引,需要进行完整的表扫描

有没有合适的方法来解决这个问题


注意:我知道单独的标签链接表提供了好处,我不必担心没有测量的性能等。我更感兴趣的是设计系统的不同方法。

单独的标签表确实是唯一的方法。这是允许无限多个标记的唯一方法。

单独的标记表实际上是唯一的方法。这是允许无限多标签的唯一方法。

想要在没有加入的情况下实现这一点,我认为这是一种过早的优化。如果经常访问此表,则它的页面很可能位于内存中,您从中读取时不会受到I/O惩罚,并且访问它的查询的计划很可能会被缓存。

想要在没有连接的情况下执行此操作,我认为这是一种过早的优化。如果经常访问此表,则其页面很可能位于内存中,并且从中读取不会招致I/O惩罚,并且访问该表的查询的计划可能会被缓存。

如果使用SQL Server,则可以使用单个文本字段(varchar(max)似乎合适)和全文索引。然后对要查找的标记进行全文搜索。

如果使用SQL Server,则可以使用单个文本字段(varchar(max)似乎合适)和全文索引。然后,只需对要查找的标记进行全文搜索。

这听起来像是一个反规范化的练习。真正需要的是一个表,它可以自然地支持您碰巧拥有的任何查询,方法是重复您本来必须连接到另一个表才能满足的任何信息。一个规范化的数据库,类似于您所拥有的数据库:

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
结果中的标题进行比较来进行这种检查。这不会导致额外的查询。如果存在不匹配,程序可以通知管理员(通过记录不一致或发送电子邮件)


修复它很容易(但在服务器工作负载方面代价高昂),扔掉多余的列并从规范化的表中重新生成它们。显然,在找到数据库不同步的原因之前,不应该这样做。

这听起来像是一个非规范化的练习。真正需要的是一个表,它可以自然地支持您碰巧拥有的任何查询,方法是重复您本来必须连接到另一个表才能满足的任何信息。一个规范化的数据库,类似于您所拥有的数据库:

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
结果中的标题进行比较来进行这种检查。这不会导致额外的查询。如果存在不匹配,程序可以通知管理员(通过记录不一致或发送电子邮件)


修复它很容易(但在服务器工作负载方面代价高昂),扔掉多余的列并从规范化的表中重新生成它们。显然,在找到数据库不同步的原因之前,不应该这样做。

适当的索引也有助于减少连接的任何惩罚。适当的索引也有助于减少连接的任何惩罚。最后,Nico是对的。我喜欢David提出的全文索引的想法(+1),但最终它并没有那么实用。最后,Nico是对的。我喜欢David提出的全文索引想法(+1),但事实并非如此