1

在试图弄清楚如何在此处使用单个 sql 语句标记博客文章时,我想到了以下想法:使用按 id 引用标签的关系表 tag2post 如下所示:

tags
+-------+-----------+
| tagid | tag       |
+-------+-----------+
|     1 | news      | 
|     2 | top-story | 
+-------+-----------+

tag2post
+----+--------+-------+
| id | postid | tagid |     
+----+--------+-------+
|  0 |    322 |     1 |
+----+--------+-------+

为什么不只使用以下模型,您可以在其中索引标签本身,如下所示?认为标签永远不会重命名,而是添加和删除,这可能是有道理的,对吧?你怎么看?

tag2post
+----+--------+-------+
| id | postid | tag   |     
+----+--------+-------+
|  1 |    322 | sun   |
+----+--------+-------+
|  2 |    322 | moon  |
+----+--------+-------+
|  3 |   4443 | sun   |
+----+--------+-------+
|  4 |   2567 | love  |
+----+--------+-------+

PS:我保留一个id,我是为了轻松显示添加的最后n 个标签...

4

5 回答 5

7

它可以工作,但没有标准化,因为标签中有冗余。您也无法使用“相同”标签来标记帖子以外的内容。对于小N,优化无关紧要,所以如果你用它运行我没有问题。

实际上,您的索引会更大(假设您要在标签上进行索引以进行搜索,您现在正在索引重复项和索引字符串)。在规范化版本中,tags 表上的索引会更小,不会有重复,tagid 上的 tag2post 表上的索引会更小。此外,固定大小的 int 列对于索引非常有效,您还可以根据您的集群选择避免一些碎片。

我知道您说不重命名,但总的来说,在这两种情况下,您可能仍然需要考虑重命名(甚至删除)标签的语义 - 是否需要更改所有条目,或者标签以某种方式分裂。因为这是最坏情况下事务中的批处理操作(所有 tag2post 都必须重命名),所以从设计的角度来看,我并没有真正将其归类为重要的。

于 2009-01-26T16:14:52.570 回答
2

这对我来说听起来不错,当你有不同的东西时,使用 ID 来引用你委托给另一个表的东西是有意义的,比如用户名或其他什么,因为你不想在数据库的每个地方都更改它的名称当他改变它时。但是在这种情况下,标签名称本身不会改变,所以我看到的唯一潜在缺点是文本索引可能比数字索引搜索要慢一些。

于 2009-01-26T16:06:16.160 回答
2

与包含 ID 的关系表相比,您的提议的真正优势在哪里?

从技术上讲,它们解决了同样的问题,但是您提出的解决方案以一种冗余的、非规范化的方式来解决,这似乎只是满足了能够直接从关系表中读取数据的本能冲动。

数据库服务器非常擅长连接表,如果连接是在一个带有索引的 INT 字段上,则更是如此。当您将另一个表(如:)加入查询时,我认为您不会面临毁灭性的性能问题INT id, VARCHAR(50) TagName

但是您失去了轻松重命名标签的能力(即使您不打算这样做),并且您不必要地用冗余数据膨胀您的关系表。随着时间的推移,这可能会比标准化解决方案花费更多的性能。

于 2009-01-26T16:33:32.767 回答
2

根据您的应用程序,反规范化方法可能很好。由于搜索大量 VARCHAR 数据,您可能会发现它会导致性能下降。

在搜索标记为“sun*”(例如 sun、sunny、sunrise)的事物时,您不需要加入。但是,您需要对更大的 VARCHAR 数据集进行类似比较。正确的索引可能会缓解这个问题,但只有测试才能告诉您哪种方法对您的数据集更快。

您还可以选择添加预连接规范化表的 VIEW。这为您提供了更简单的查询,同时仍然允许您拥有高度规范化的数据。

我的建议是使用规范化结构(并添加非规范化视图以方便使用),直到遇到非规范化数据模式修复的问题。

于 2009-01-26T16:46:56.873 回答
0

我也在考虑这个。想要数据库中的标签列表,只需从 tag2post 中选择不同的标签。有人告诉我,由于我想针对 select 语句进行优化,所以最好使用整数键,因为它比使用字符串快得多。

于 2009-01-26T16:16:56.763 回答