最好使用包含大量对象或大量文档的文档?

时间:2016-05-26 22:31:01

标签: javascript mongodb optimization query-optimization

所以我有一些关于公司很多人的数据,比如姓名,年龄和性别。我将把他们的信息存储在MongoDB中。我将它们的信息存储在很多文档中或作为一堆独立的对象存储在一个文档中会不会更好?是否有任何性能或内存问题会使一种方法优于另一种方法?

存储数据的示例方法:

大量文件

{
  _id: ObjectId('1'),
  name: 'Bart',
  age: 10,
  gender: 'Male'
},
{
  _id: ObjectId('2'),
  name: 'Lisa',
  age: 8,
  gender: 'Female'
}

一个文档中的大量对象

{
  _id: ObjectId('1'),
  'Bart': {
    age: 10,
    gender: 'Male'
  },
  'Lisa': {
    age: 8,
    gender: 'Female'
  }
}

对于任何想知道我用Mongo的投影参数查询第二个例子的人,例如

db.families.find({_id:ObjectId('1')},{_id:0,'Bart':1});

另外,我问这个的唯一原因是因为我打算在这里存储来自多家公司的人。它们将通过集合和单独列出的人员分开,如第一个示例或文档中的文档以及单独列为公司文档中的对象的人员。

1 个答案:

答案 0 :(得分:4)

第一个是可取的。

每个文档都有16 MB的限制。因此,将所有内容放在单个文档中更有可能遇到这个障碍,您必须手动执行文档拆分,并最终获得同一(伪)集合的多个文档。您需要额外的程序代码才能找到正确的片段,甚至可以将应用程序中的文档组合起来执行一些集合级操作。除非有非常这样做的理由,否则我会不惜一切代价避免这种情况。

此外,它可能最适合您的访问模式。您还有更多优化选项,例如您可以在名称上定义索引,而第二个示例无法做到。同样,文档越小,更新该文档的速度就越快(特别是在没有就地更新的情况下)。

如果您打算让多个公司拥有用户,您可以为每个公司使用单独的集合,也可以在文档中添加公司属性。这取决于你将支持多少公司,但假设它不只是2或3,我更喜欢后一种选择。它更易于维护,缩放(即分片),优化(索引等)或扩展。

{
  _id: ObjectId('1'),
  name: 'Bart',
  age: 10,
  gender: 'Male'
  company: 'XYZ'
}

修改

有关性能的更多考虑因素。两种选择的基本事件流程如下:

1-doc策略(带投影)

  1. 使用index(内存中)快速
  2. 按objectId查找文档
  3. 根据文档的大小加载整个文档(来自dics),可能很慢
  4. 投影(在记忆中)快速
  5. n-doc策略(无投影)

    1. 按objectId或名称查找文档,使用索引(在内存中),快速
    2. 从光盘加载(小)文档,速度慢,但比加载大文档更快
    3. 特别是对于1-doc策略,当它比n-doc策略慢时,可能会有一个转折点,特别是当文档变大时。对于较小的文档,它可能相同或者更快,特别是当缓存发挥作用或其他边缘情况发生时(即名称范围有限,这使得对名称的查询不是很有选择性,但在这种情况下你会被搞砸无论如何使用1-doc方法)

      Mongo对模式设计的建议如下:

      • 1:1关系:使用嵌入式文档
      • 1:关系不多:使用嵌入式文档
      • 1:许多人使用多个集合

      你打算做的是建立公司:人际关系,这可能是第三种或第二种选择。所以要么你有两个集合:

      • 公司
      • 人(公司的外键)

      • 公司(嵌入人员)

      无论哪种方式,我都会将此人塑造为

      person:
      {
        _id: ObjectId('1'),
        name: 'Bart',
        age: 10,
        gender: 'Male'
        company: 'XYZ' //only for foreign key relationship to separate collection
      }
      

      对于嵌入式人员,它是公司中的阵列

      company:
      {
        name: 'companyA',
        persons: [..] //and not use person's name as key here
      }
      

      我可以在persons.name和/或company上添加索引。因此,搜索单个人完全在内存中运行(使用索引)并且加载人员文档应该很快,因为只从光盘读取一个小文档。

      因此,这些方法中的任何一种都为我提供了最高的灵活性,同时仍然非常快速地访问。

      虽然可能存在这样的情况,但是当投影速度很快时(可能是在拥有小型公司"文件且已经缓存的情况下),我不会这样做,因为它有一些严重的缺点(其中一些也会对性能产生负面影响)。

      • 你不能拥有人的索引
      • 如果文档超过16MB(最终可能会发生),则需要额外的应用程序逻辑
      • 你不能处理相同的名字(可能会发生)
      • 你的灵活性较低(更改模式,在分布式环境中选择更新操作的原子性,添加附加访问模式,如列出公司的所有人员)
      • 维护可能会变得很麻烦(你必须反省公司文件以找到人的名字)
      • 可能存在分片或复制的副作用,我现在没有想到
      • 它违反了oo设计原则(问自己:Bart' Bart是一个家庭的财产,还是一个儿子或者更普遍的儿童'?) - 使其不易维护

      因此,即使没有证明一个appproach比另一个更快,我也不会采用预测方法来过滤用户,因为这些缺点远远超过了(假设的)优势。