MongoDB结构:单个集合 vs 多个较小的集合

32

我有一个关于通用数据库结构的问题,在我的场景中我恰巧正在使用mongodb。

我正在创建一个应用程序,用户可以上传歌曲列表(标题,艺术家等),但我不确定是否应该为所有用户建立一个songList集合,还是为每个单独的用户建立一个songList.user#集合。 用户只能查询与他们相关的歌曲,因此用户A永远不会知道用户B的歌曲。

代码示例:

每个用户多个集合

db.songList.userA.find()
{"title": "Some song of user A", "artist": "Some artist of user A"}

db.songList.userB.find()
{"title": "Some song of user B", "artist": "Some artist of user B"}
  • 优点
    • 查询的集合大小较小
  • 缺点
    • 可维护性
      • 1,000个用户意味着有1,000个集合

与包含拥有“用户”字段的单个集合相比

db.songList.find({"user":"A"})
{"title": "Some song of user A", "artist": "Some artist of user A", "user": "A"}
  • 优点
    • 如果需要,可以灵活查询跨用户
  • 缺点
    • 性能

我正在试图建立一个赞成/反对清单,但仍然摇摆不定。 鉴于每个用户的歌曲将被彼此隔离,哪种方法更好? 我最关心的是维护和查询性能。

提前致谢。


3
不要担心这种事情,去建立一些东西。通过建立它而不是担心细节,您可能会发现哪种方法最有效。 - SomeKittens
1
同意@SomeKittens的观点。话虽如此,我会按用户来做,因为这样更容易犯错,把A的歌曲显示给B。无论如何,如果/当我有足够的用户时,我会担心优化问题。 - Diego Basch
就安全性而言,每个用户拥有一个集合可以使用Mongodb的集合级别访问控制机制。通过这种方式,可以在数据库级别上确保一个用户永远不会访问另一个用户的数据。 - Boris van Schooten
@Steven,我很好奇你最终选择了哪种设计,因为我目前也面临着类似的困境。 - MadPhysicist
2个回答

16

我建议不要为每个用户创建单独的集合。

请阅读文档

默认情况下,MongoDB数据库的命名空间限制约为24,000个。 每个命名空间为628字节,默认情况下,.ns文件大小为16MB。

每个集合都算作一个命名空间,每个索引也是如此。 因此,如果每个集合都有一个索引,我们最多可以创建12,000个集合。 --nssize参数允许您增加此限制(请参见下文)。

请注意,每个集合都有一定的最小开销--几KB。 此外,任何索引将至少需要8KB的数据空间,因为b-tree页面大小为8KB。 如果有很多集合并且元数据被分页出去,则某些操作可能会变慢。

因此,如果您的用户超过命名空间限制,您将无法优雅地处理它。 另外,随着用户基数的增长,性能也会下降。

更新

正如@Henry Liu在评论中提到的,对于使用WiredTiger存储引擎的Mongodb 3.0或更高版本,它将不再受到此限制。

docs.mongodb.org/manual/reference/limits/#namespaces


感谢提供的信息,但接下来的段落描述了如何使用--nssize来增加此限制(最大.ns文件大小为2GB)。因此,如果每个songList集合只有1个索引,理论上我可以拥有240,000多个集合,而不会接近2GB的限制。(如果每个集合有2个索引,则此限制几乎减半)。 - Steven
你可以按照自己的方式进行建模。我只是推荐了一种优雅的方法 :) - Sushant Gupta
谢谢您的帮助,阅读了这些信息后,我发现多个集合似乎并不必要,因为我可以在单个集合中完成所需的操作,同时避免命名空间限制。 - Steven
1
从mongodb 3.0或更高版本开始,如果您使用WiredTiger存储引擎,则将不再受到限制。https://docs.mongodb.org/manual/reference/limits/#namespaces - Henry Liu
谢谢@HenryLiu,我早在2012年就写下了这个答案。感谢你更新信息。我已经在我的回答中添加了更新内容。 - Sushant Gupta

9

MongoDB在水平方向上具有出色的扩展性。它可以将集合分片到动态集群中,以产生一个快速、可查询的数据集合。

因此,拥有较小的集合大小并不是一个优点,我不确定这个理论从何而来,它既不适用于SQL也不适用于MongoDB。如果分片的性能良好,则其性能应该相对于查询单个小的数据集合(带有一定开销)。如果不是这样,那么您的分片设置可能存在问题。

MongoDB在垂直方向上并不擅长扩展,正如@Sushant所引用的那样,MongoDB的ns大小会成为一个严重的限制。这个引用没有提到的一件事是索引的大小和数量也会影响ns的大小,因此描述了以下内容:

因此,如果每个集合都有一个索引,我们最多可以创建12,000个集合。--nssize参数允许您增加此限制(请参阅下文)。


我曾经阅读过这篇文章,它让我相信使用多个较小的集合会带来显著的性能提升。你是在说,如果我有一个以用户字段为分片键的集合,我也应该看到类似的性能提升吗? - Steven
有太多未知因素,无法确定他为什么会得到那些查询时间,查询时间非常依赖于硬件、索引、数据、规范化等。然而,他确实指出当他有大量记录时,查询很快,问题是当他在索引中使用少量选择性(价格>100的类型记录较少)时,这让我相信他的索引对于他的查询并不是很好。 - Sammaye
1
是的,像 user_id 这样的分片键(这里有一点猜测,你应该真的真的真的为你的数据进行研究)会为包含 user_id 的查询产生不错的返回结果。然而,这并不是分片的全部情况,我强烈建议在立即认为 user_id 可以解决你的分片问题之前,在这里和谷歌上进行一些搜索。 - Sammaye
1
谢谢您的帮助,如果我在实施单个集合后需要优化查询性能,我会进行更多的研究并尝试使用分片。 - Steven

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接