更新集合中的大量记录

时间:2013-08-24 06:37:20

标签: mongodb

我的名为TimeSheet的集合现在有几千条记录。这最终将在一年内增加到3亿条记录。在这个集合中,我嵌入了来自另一个名为Department的集合中的几个字段,其中大多数都不会获得任何更新,并且很少会更新某些记录。我很少说一年只有一次或两次,也不是所有记录,只有不到1%的记录。

大多数情况下,一旦创建了一个部门,就不会有任何更新,即使有更新,它也会在最初完成(当TimeSheet中的相关记录不多时)

现在,如果有人在一年后更新某个部门,在最糟糕的情况下,收集TimeSheet将有大约3亿条记录,大约有500万条匹配记录可供更新。更新查询条件将位于索引字段上。

由于这次更新非常耗时并且会产生锁定,我想知道有没有更好的方法呢?我正在考虑的一个选项是通过添加UpdatedDateTime> somedate && UpdatedDateTime < somedate等额外条件来批量运行更新查询。

其他细节:

单个文档大小可能约为3或4 KB 我们有一个包含三个副本的副本集。

还有其他更好的方法吗?您如何看待这种设计?如果我给出的数字不像下面那么你觉得怎么样?

1)更新查询的1亿条记录和100,000条匹配记录

2)更新查询总计1000万条记录和10,000条匹配记录

3)更新查询总计100万条记录和1000条匹配记录

注意:集合名称departmenttimesheet及其目的是虚构的,而不是真正的集合,但我提供的统计数据是真实的。

1 个答案:

答案 0 :(得分:11)

让我根据我的全球知识和经验给你一些提示:

使用较短的字段名称

MongoDB为每个文档存储相同的密钥。这种重复导致磁盘空间增加。这可能会在像您这样的巨大数据库上出现性能问题。

优点:

  • 文档尺寸减小,磁盘空间减少
  • 更多文档适合RAM(更多缓存)
  • 在某些情况下,do索引的大小会更少

缺点:

  • 不太可读的名字

优化索引大小

索引大小越小,它在RAM中的适应性越大,发生的索引丢失越少。例如,考虑git提交的SHA1哈希。 git commit多次由前5-6个字符表示。然后只需存储5-6个字符而不是全部哈希值。

了解填充因子

对于文档中发生的更新导致代价高昂的文档移动。此文档移动导致删除旧文档并将其更新到新的空位置并更新成本高昂的索引。

如果发生某些更新,我们需要确保文档不会移动。对于每个集合,都有一个填充因子,在文档插入期间,它会告诉除了实际文档大小之外还要分配多少额外空间。

您可以使用以下方式查看集合填充因子:

db.collection.stats().paddingFactor

手动添加填充

在您的情况下,您非常肯定会从一个将会增长的小文档开始。在while之后更新文档将导致多个文档移动。因此,最好为文档添加填充。不幸的是,没有简单的方法来添加填充。我们可以通过在执行插入时向某个键添加一些随机字节来执行此操作,然后在下一个更新查询中删除该键。

最后,如果您确定将来某些密钥会出现在文档中,那么请使用某些默认值预先分配这些密钥,以便进一步更新不会导致文档大小增加,从而导致文档移动。

您可以获取导致文档移动的查询的详细信息:

db.system.profile.find({ moved: { $exists : true } })

大量集合VS少量集合中的大量文档

Schema取决于应用程序要求。如果有一个巨大的集合,我们只查询最近N天的数据,那么我们可以选择单独收集,旧数据可以安全存档。这将确保RAM中的缓存正确完成。

创建的每个集合都会产生超出创建集合成本的成本。每个集合都有一个最小大小,即几KB和一个索引(8 KB)。每个集合都有一个关联的命名空间,默认情况下我们有一些24K的命名空间。例如,每个用户拥有一个集合是一个糟糕的选择,因为它不可扩展。在某些方面之后,Mongo将不允许我们创建新的索引集合。

通常具有许多集合没有显着的性能损失。例如,如果我们知道我们总是根据月份进行查询,我们可以选择每月收集一个。

数据的非规范化

始终建议在同一磁盘位置保留查询或查询序列的所有相关数据。您需要在不同文档中复制信息。例如,在博客文章中,您需要将帖子的评论存储在帖子文档中。

优点:

  • 索引大小将会非常少,因为索引条目的数量将会减少
  • 查询将非常快,包括获取所有必要的详细信息
  • 文档大小将与页面大小相当,这意味着当我们将这些数据放入RAM时,大部分时间我们都不会在页面上引入其他数据
  • 文档移动将确保我们释放页面,而不是页面中可能不会用于进一步插入的小块

上限收藏

上限集合的行为类似于循环缓冲区。它们是特殊类型的固定大小的集合。这些集合可以接收非常高速的写入和顺序读取。固定大小,一旦填充分配的空间,新文档将通过删除旧文档来编写。但是,只有在更新的文档符合原始文档大小时才允许文档更新(使用填充进行播放以获得更大的灵活性)。

相关问题