9

TimeSheet我现在有几千条记录的集合。这最终将在一年内增加到 3 亿条记录。在这个集合中,我嵌入了另一个集合Department中的几个字段,该集合通常不会得到任何更新,并且很少会更新一些记录。很少是指一年只有一次或两次,也不是所有记录,只有不到集合中记录的 1%。

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

现在,如果有人在一年后更新一个部门,在最坏的情况下,有可能集合TimeSheet总共有大约 3 亿条记录,并且更新的部门大约有 500 万条匹配记录。更新查询条件将在索引字段上。

由于此更新很耗时并会创建锁,我想知道有没有更好的方法来做到这一点?我正在考虑的一个选项是通过添加额外的条件来批量运行更新查询,例如UpdatedDateTime> somedate && UpdatedDateTime < somedate.

其他详情:

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

有没有其他更好的方法来做到这一点?您如何看待这种设计?如果我给出的数字不像下面那样,你怎么看?

1)更新查询总记录1亿条,匹配记录10万条

2) 1000万条总记录和10000条匹配记录用于更新查询

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

注意:集合名称departmenttimesheet,以及它们的用途是虚构的,不是真实的集合,但我给出的统计数据是真实的。

4

1 回答 1

12

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

使用较短的字段名称

MongoDB 为每个文档存储相同的键。这种重复会导致磁盘空间增加。在像您这样的非常庞大的数据库上,这可能会产生一些性能问题。

优点:

  • 文档的大小更小,因此磁盘空间更小
  • 更多文件以适应 RAM(更多缓存)
  • 在某些情况下,do 索引的大小会更小

缺点:

  • 可读性较差的名称

优化索引大小

索引大小越小,它就越适合 RAM,索引未命中的情况就越少。例如,考虑 git 提交的 SHA1 哈希。一个 git commit 多次由前 5-6 个字符表示。然后只需存储 5-6 个字符而不是所有哈希。

了解填充因子

对于文档中发生的更新导致昂贵的文档移动。该文档移动导致删除旧文档并将其更新到新的空位置并更新索引,这是昂贵的。

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

您可以使用以下命令查看集合填充因子:

db.collection.stats().paddingFactor

手动添加填充

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

最后,如果您确定某些键将来会出现在文档中,则使用一些默认值预先分配这些键,以便进一步更新不会导致文档大小的增长导致文档移动。

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

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

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

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

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

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

数据的非规范化

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

优点:

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

封顶集合

Capped 集合的行为类似于循环缓冲区。它们是特殊类型的固定大小的集合。这些集合可以接收非常高速的写入和顺序读取。由于是固定大小,一旦分配的空间被填满,新的文件就会通过删除旧的文件来写入。但是,仅当更新的文档适合原始文档大小时才允许文档更新(使用填充以获得更大的灵活性)。

于 2013-08-24T09:33:42.547 回答