【问题标题】:Database design for hashtags in MySQLMySQL中标签的数据库设计
【发布时间】:2016-05-18 22:49:33
【问题描述】:

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

1) 我的第一个设计理念(也许更传统)是 3-table 设计:

  • 第一个表只存储了帖子内容和其他相关数据 到帖子本身(我已经在使用这样的表格了)。
  • 第二个表只是存储正在使用的新主题标签,基本上用作查找所有已使用的主题标签。
  • 第三个表是定义主题标签和帖子之间关系的表。所以基本上是一个简单的表 会有一个带有帖子 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 相关联的帖子。理想情况下,我还希望能够从数据库中检索帖子的主题标签,因为它是由用户在帖子内容中进行样式化的。在这一点上,围绕分析主题标签的所有其他查询和功能都是次要的。

【问题讨论】:

  • 采用第一种方法,因为它可以保持可扩展性。此外,对于具有原始格式的主题标签列表,您只需要确保您显示的主题标签来自帖子本身而不是来自列表(您始终可以再次从帖子中获取主题标签)
  • @AkshatSinghal。这也是我在想的,只是从帖子内容中检索原始内容,但有没有有效的方法来做到这一点(sql、php 或其他)。因为我将不得不从一段文本中过滤掉它,所以我可能不得不使用正则表达式左右,如果我在一个页面加载的多个帖子上这样做,我担心速度和效率。有什么想法吗?
  • 如果我采用第一种设计,在尝试检索帖子时必须在查询中使用额外的 JOIN 的效率有什么想法吗?即使表格变得非常大,它是否可以忽略不计?
  • @arian1123 用于从帖子中检索原始主题标签,您可以使用以下方法:通过搜索主题标签(将所有主题标签保持小写)获取帖子中主题标签的字符串位置帖子(strtolower),然后提取原始主题标签。这将使您免于使用正则表达式或通配符。

标签: php mysql database


【解决方案1】:

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

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


至于解决查询的不区分大小写的搜索部分,您的 dbms 很可能有一些排序选项,您可以在架构中指定(例如 utf8_general_ci),其中 ci 表示架构中不区分大小写的比较.也就是说,数据将按原样存储,但是当在查询中与另一个值进行比较时,MySQL 会以不区分大小写的方式进行字符比较。

【讨论】:

  • 优秀的答案。只是关于区分大小写部分的问题:当我创建决定是否将新标签添加到查找表或它是否已经存在的逻辑时,如果我使用ci,如果样式不同,它会注册一个标签吗?例如,它是否会同时注册“测试”和“测试”。如果是这样,它将为本质上相同的主题标签创建 2 个不同的 ID。然后,当我按名称搜索主题标签时,它会返回 2 个 ID,还是只返回 1 个?如果它确实返回 2 个 ID 以与 post 匹配,这是否比仅搜索 1 更低效?
  • 是的,排序规则只影响 MySQL 如何比较值,而不影响它如何存储它们。至于您是否希望这两个主题标签是唯一的,这完全取决于您的设计。因此,例如,可以将主题标签以全小写形式存储在查找表中,并且帖子本身将包含用户提交的数据。这样,标签表的唯一目的就是建立索引。
  • 我想我可能会将它们全部小写。似乎是合理的做法。当尝试仅列出主题标签时,挑战就变成了从帖子内容中提取主题标签的有效设计。将一些 ID-名称关系也存储在 memcache 中是个好主意。我会接受这个答案。
  • 非常有道理的@Sherif。拥有所有主题标签的单个表格还允许您在其旁边放置例外表格,以便可以将拼写错误作为一个条目放在一起,例如yu 可能希望将 Pampalona Pamplona 和 Pamps 的主题标签合并为一个标签,或者有​​一个排除表,例如#1 #2。
  • Inmy 相信这个问题的例子是错误的。在此示例中,我们没有更新。我们有删除和插入。
猜你喜欢
  • 1970-01-01
  • 2018-11-20
  • 2010-11-30
  • 2017-01-18
  • 2018-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多