0

TLDR;将两种不同类型的文档放在同一个集合中以节省到数据库的往返行程是否有缺点?

所以我有孩子的文档,以及父母中引用孩子的键列表,几乎每当我们想要父母时,我们也希望孩子们一起来。最简单的方法是获取父节点,然后使用带有 $IN 的子键列表获取子节点(在 SQL 中,我们将使用连接)。但是,这意味着为相当频繁的操作进行 2 次往返。我们有几个选项可以改进这一点,特别是因为我们可以在检索父键的同时检索子键:

  1. 将孩子放在父文档中

    虽然这会发挥 mongo 的优势,但我们也希望保持这些数据标准化

  2. 线程中的管道数据库请求

    一旦我们将连接池考虑在内,这可能会或可能不会提高性能。这也意味着在 python 应用程序中处理线程,这并不可怕,但也不是很好。

  3. 将父/子文档保存在同一个集合中(不嵌入)

    这样我们就可以一次查询所有的键;这确实意味着包装器中用于访问数据库的一些概念开销,并强制所有索引都是稀疏的,但否则看起来很简单。

我们可以分析所有这些选项,但尽管没有在网上找到任何东西,但确实感觉那里的人应该已经有了这方面的经验。那么,我的分析中是否遗漏了什么?

4

2 回答 2

1

我将分别讨论这三点。您应该知道,这绝对取决于哪种情况最有效。没有“理论上正确”的答案,因为它取决于您的数据存储/访问模式。

  1. 关于如何存储数据始终是一个相当复杂的决定。我认为主要规则应该是“我如何查询我的数据?”,而不是“我们希望所有数据都标准化”。数据规范化是您为关系数据库而不是 MongoDB 所做的事情。如果您几乎总是与父项一起查询子项,并且您没有未绑定的子项列表,那么您应该这样存储它们。请注意,MongoDB 中的文档限制为 16MB(这比您想象的要多得多)。

  2. 避免穿线。您最好从两个不同的集合中依次运行两个查询。不太复杂是一件好事!

  3. 这可行,但这是一种相当丑陋的方式。但话又说回来,丑陋并不总是一件坏事,如果它能让事情进展得更快。当然,我不太清楚您的父文档和子文档有多不同,因此很难说这是否是一个好的解决方案。一个稀疏索引,我假设您将根据它是父还是子在特定字段上执行,这是一个好主意。但也许您也可以使用一个索引。在您展示建议的架构后,我很乐意更新您的答案。

我建议您进行一些基准测试,但忘记选项 2。

于 2013-02-08T20:41:22.193 回答
0

如果层次结构中有更多级别(对于一个级别也可以正常工作),那么拥有一组祖先是一个不错的选择。这是一种不是我发明的技巧,当然它在 mongodb 开发人员课程中进行了解释:https ://education.10gen.com/courses (这只是一个链接,您可以在其中找到我无法链接到的诅咒教程直接)。在这种情况下,您有一个 id 数组,其中至少包含节点本身和所有祖先 id。如果您查询子树,您只需在祖先数组中搜索根。

这些文件包含:

{ancestors: [2,7,6]}

您查询节点 6 下的子树:

find({ancestors:6})

这很好,但在现实世界的示例中,您通常不会查询 id。因此,您将有两个查询,一个用于有意义的事物,一个用于 id 属于该事物的查询。

但是,如果您在第一步查询 id,则此解决方案可以解决您的问题。

我认为由于 mongodb 很多事情都取决于父子关系的结构。如果只有一个级别的沿袭,则没有真正特别的理由单独存储数据,在这种情况下,丑陋的方式是不错的选择,甚至如果您可能对其进行复杂的查询(和索引),请使用非规范化.

(您实际上没有机会查询父母的某些特征并在同一个查询中检索孩子而不进行反规范化/嵌入),但仅当您有很少的连接时才嵌入,并且仅当您不复制大量数据时才进行非规范化。如果您将子 id 存储在一个数组中(并对其进行索引),这两个查询的性能不会那么糟糕,与保持非规范化数据的清洁或使用嵌入处理 16MB 限制相比,这并不是一个坏主意。

于 2013-02-09T09:40:31.980 回答