【问题标题】:mysql one-to-many table vs. key-value database listmysql 一对多表 vs. 键值数据库列表
【发布时间】:2013-02-03 09:37:00
【问题描述】:

我正在构建一个评论系统,一个评论可以有很多回复。

如果我要在 mysql 中实现这个,我会建立一个comments 表,并有列:

  • comment_id,
  • parent_comment_id

评论的父评论 id 为 0,回复的父评论 id。因此,如果我正在寻找对某个评论的回复,我会寻找具有parent_comment_id 的 cmets 来匹配我正在寻找的评论。

这对我来说似乎是多余的,因为它需要我遍历整个 comments 表来查找评论是否有回复(尤其是对于大数据),如果我有一个密钥库数据库,我将有一个评论 ID 的键,其中将是按日期排序的回复列表。

那么您认为哪种方法更能解决这个问题?

另外,我想将问题概括为任何一对多关系,以将其作为列表存储在密钥库数据库中。如果您推荐使用密钥库数据库,您会推荐哪一个来处理大数据? (我不想使用 redis,因为它是在内存中的,我怀疑对 cme​​ts 的回复需要经常访问)。

感谢您的回复。

【问题讨论】:

  • 您有数据库性能问题吗?关系数据库不适用于树结构,但如果将它限制在一个级别,如果 cmets 可能会有更好的性能,并且您可以使用自连接来一次获取所有 cmets。不管你要设置什么,说你有新的 cmets,等等。
  • 我没有任何数据库性能问题,因为我还没有开始,我只是想在这里理论上谈谈。我确实有一级 cmets,仅此而已,但我希望桌子非常大。请问自加入是什么意思:)?
  • self join 意味着 SQL 查询将在查询中多次引用其自身。喜欢select main.*, child.* comments main join comments child on main.id = child.parent_id where main.id = 1;

标签: mysql database database-design nosql database-performance


【解决方案1】:

关系数据库应该可以很好地处理这种“邻接表”模型。

首先,“root”注释的parent_comment_id中不要使用0,使用NULL。然后,您可以构建一个从 parent_comment_idcomment_id 的 FOREIGN KEY,以防止您错误地将回复附加到不存在的评论。

这需要我浏览整个 cmets 表才能找到评论是否有回复

假设您已索引parent_comment_id(如果您在上面创建了 FK,则为InnoDB did automatically),查找对给定评论的第一级回复将需要索引范围扫描。要了解索引范围扫描及其高效的原因,您首先需要了解Anatomy of an SQL Index

找到第二个级别需要再次进行范围扫描等。不幸的是,MySQL 不支持递归查询,该查询允许您在单个数据库往返中完成所有这些操作,但它应该仍然相当有效。

如果您进行了测量并得出结论认为这是一个问题,那么还有其他表示层次结构的策略(具有不同的权衡),例如“嵌套集”和“闭包”。看看this presentation by Bill Karwin

【讨论】:

  • 关于mysql部分问题的好答案。我只使用一级父母身份,所以我只需要为索引创建外键,我应该没问题。我将为此使用 mysql,但我仍然认为密钥库数据库更适合列表,因为您正在寻找 1 个键来查找主键列表,可能是因为我不了解 mysql 背后的底层算法。谢谢。
【解决方案2】:

事实上,大多数关系数据库不必通过所有的 cmets 来找出给定评论的回复。毕竟这些类型的查询非常频繁并且非常优化。还可以考虑在parent_comment_id 上构建索引。同样,这仅在您拥有单一级别的亲子关系时才有效。如果您可能有一个评论轮流评论,那么另一种存储数据的方式可能会更好地为您服务。

【讨论】:

  • 好吧,我的大部分关系都会有一层亲子关系。 cmets 示例只是其中之一。所以你认为在 parent_comment_id 上建立索引对于大型数据集就足够了。我希望 cmets 表非常大。对我来说,有一个键列表在解决这个问题时更有意义,因为您只需要找到一个键即可找到列表,然后在表中通过 id 查找它们。但我猜你是说 mysql 更适合处理此类查询。
  • 我认为构建索引应该可以很好地优化事物。我建议您在构建索引后尝试一些示例查询并查看性能。仅使用密钥库并不令人满意。使用数据库,您将为您实现许多功能,例如聚合函数,而使用密钥库,您可能不得不重新发明轮子。
  • 我将使用索引,看看它是如何进行的。谢谢老哥
  • 我同意没有父级的评论在 parent_comment_id 字段中应为 NULL 而不是零。我也同意索引会大大加快搜索回复的速度。
【解决方案3】:

您可以创建表格并使其更加灵活。

cmets => comment_id, the_comment, count_replays

cmets_replay => parent_id, the_comment

当有评论重播时,count_replays 会有更新。

如果有回放,现在你可以做 if 语句,然后才请求它们。

【讨论】:

  • 谢谢,我将使用replies_count 来检查我是否需要获取回复。拥有两个表也很整洁有序,但会增加迁移的复杂性或未来可能的分片。
【解决方案4】:

赞成 Branko 的回复。父字段上的索引很好。在这种情况下,NULLS 比零工作得更好。另外,参照完整性约束对您的帮助大于对您的伤害。

加分。

如果您使用 方法而不是现有的邻接列表方法,您将能够搜索由回复和对回复的回复等组成的整个子树,而不仅仅是立即回复。这可能很有用。

其次,有一种称为“森林”的数据结构。这是一个包含一组树的表,其中每棵树都具有作为其根的,在本例中是一个没有父级的注释。网络搜索应该为您提供一些关于设计讨论森林的好文章,其中每个讨论都以评论开始,每个讨论都是回复树。很多人都设计过这种情况。

【讨论】:

  • 我将使用 NULL,但对于我的应用程序,我将使用 1 级父母身份,因此不需要森林结构,我会阅读更多内容以供启发。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多