MySQL 中主题标签的数据库设计

ari*_*123 5 php mysql database

我目前正在开发能够在我们的网站上使用主题标签的系统,但我在如何最好、最有效地在数据库中存储主题标签方面遇到了一些麻烦。需要进行设计,以便检索与搜索词匹配的帖子相对简单(例如在 Twitter 上,当您单击主题标签的链接时,它会显示带有该主题标签的所有推文)。主题标签将通过从创建的帖子(也类似于 Twitter)的内容中提取术语并插入它们来存储在数据库中。如何插入它们当然是当前的问题:目前我在两种可能的设计之间左右为难:

1)我的第一个设计想法(也许更传统)是3表设计:

  • 第一个表仅存储帖子内容和与帖子本身相关的其他数据(我已经使用这样的表)。
  • 第二个表仅存储正在使用的新主题标签,基本上用作查找已使用的所有主题标签。
  • 第三个表是定义主题标签和帖子之间关系的表。所以基本上是一个简单的表,其中一列包含帖子的 ID,另一列包含我们存储在上一个表中的单个主题标签的 ID。因此,例如,具有 3 个主题标签的帖子将在此表中包含 3 行,其中 1 行对应与其关联的每个主题标签。

2)第二种设计是2-table设计:

  • 同一张表,其中存储了发布数据,如上所示。
  • 第二个表是第一个设计中第二个和第三个表的混合:它保存主题标签和帖子之间的关系之间的数据,但它不是将新主题标签存储在为其分配 ID 的表中,而是仅存储实际的主题标签(例如“#test”)本身以及帖子的 ID。同样的概念也适用于此,如果一篇文章中有 3 个主题标签,它将在表中存储 3 个单独的行。

我在这些想法之间左右为难的原因是因为第一个选项似乎确实是更标准的方法,而且似乎有更多的“结构”。然而,由于它们是主题标签,因此我没有看到为每个主题标签实际分配唯一 ID 的太多目的,因为主题标签不是真正的分类,例如类别或流派等。

另外,当我尝试创建主题标签的搜索页面时,我必须使用更少的 JOIN,因为我不需要查找搜索术语的 ID,然后转到另一个表并找到具有该 ID 的关联帖子。

此外,当尝试简单地列出帖子的主题标签时,有点烦人的一件事是主题标签的打印结果可能与用户在帖子中对其进行风格化的方式不同。例如,如果一个用户添加了 #testing,但另一个用户之前输入了带有 #TeStIng 的帖子,则该帖子的主题标签将打印出 #TeStIng,因为这就是它保存在数据库查找表中的方式。当然,您可以使其区分大小写,但在搜索中 #testing 和 #TeStIng 应被视为相同的主题标签,这样可能会变得混乱。还是我在这件事上错了?有人对如何避免这种情况有建议吗?

另一方面,我对第二个表设计的担忧是,如果表变得很大,它可能会变得低效,因为查找字符串比搜索整数慢(我将在第一个设计中这样做)。但是,由于我必须在第一个设计中使用更多的 JOIN,实际上会存在性能差异吗?需要明确的是,当搜索字符串本身时,我将使用 = 运算符而不是 LIKE。

同样,我想如果我想查询主题标签本身,例如有多少帖子正在使用某个主题标签以及类似的东西,那么第一个设计会更有效,尽管第二个设计也不会很困难,我只是再次想知道效率。

有什么想法可以更好地发挥作用吗?最重要的是,通过主题标签搜索是有效的,因此例如我试图查找与 #test 相关联的帖子。理想情况下,我还希望能够从数据库中检索帖子的主题标签,因为它是由用户在帖子内容中风格化的。此时,围绕分析主题标签的所有其他查询和功能都是次要的。

She*_*rif 5

纯粹从数据库规范化的角度来看,您的第二个设计不会在3NF中。您依赖整个主键而不依赖键是有原因的。如果哈希表中的任何更改对帖子表有直接影响,则会出现逻辑不一致。例如,主题标签表有两行:一行带有主题标签#politics,另一行带有主题标签#politic。假设为第二个主题标签创建帖子的人决定编辑他们的帖子并将主题标签更新为#politics可能是因为他们输入错误)。您更新哪一行?

至于性能,对于第一个设计我一点也不担心。您的数据库(就像当今几乎所有主要的关系数据库管理系统一样)依赖于一种称为二叉搜索树(或更具体地说是红黑树)的东西来优化数据库表中插入/删除/搜索的成本。索引这些值。在某些文本搜索用例中,它可以使用 O(1) (哈希表查找)进一步优化这一点,或者您甚至可以自己在 Memcached/Redis 等键/值缓存存储中执行此操作。在大多数情况下,对主题标签进行索引以便更快地搜索使用这些主题标签的帖子绝对是您想要的设计。由于最大的成本因素不是查找单个主题标签(我假设在此用例中大多数搜索都会有一个主题标签),而是检索包含该主题标签的所有帖子。


至于解决查询中不区分大小写的搜索部分,您的 dbms 很可能具有一些可以在模式中指定的排序规则选项(如utf8_general_ci),其中ci代表模式中不区分大小写的比较。这意味着,数据将按原样存储,但是当在查询中与另一个值进行比较时,MySQL 将以不区分大小写的方式进行字符比较。