21

我需要存储数十亿个小型数据结构(每个大约 200 字节)。到目前为止,将每个元素存储为单独的文档效果很好,Mongo 每秒可提供大约 10,000 个结果。我使用 20 字节散列作为每个文档的 _id,并在 _id 字段上使用单个索引。在测试中,这适用于包含 5,000,000 个文档的数据集。

在操作中,我们将每秒发出大约 10,000 个请求,每秒更新大约 1,000 次现有文档,每秒可能插入 100 次或更少的新文档。

当我们无法在 RAM 中存储整个索引时,我们如何管理更大的数据集?如果我们将多个元素组合到每个文档中,MongoDB 的性能是否会更好——以便更快地搜索索引,但在每个查询中返回更多数据?

与其他关于 SO 的问题不同,我不仅对我们可以将多少数据填充到 Mongo 中感兴趣。它可以清楚地管理我们正在查看的数据量。find我担心的是,在有限的 RAM的情况下,我们如何才能最大限度地提高大型集合的操作速度。

我们的搜索将趋于聚集;大约 50,000 个元素将满足大约 50% 的查询,但其余 50% 将随机分布在所有数据中。我们是否可以通过将这 50% 的数据移动到他们自己的集合中来获得性能提升,以便将最常用数据的较小索引始终保留在 ram 中?

将 _id 字段的大小从 20 字节减少到 8 字节会对 MnogoDB 的索引速度产生重大影响吗?

4

1 回答 1

28

我想到了一些策略:

1) 为“热”文档使用不同的集合/数据库。

如果您知道哪些文档在热集中,是的,将它们移动到单独的集合中会有所帮助。这将确保热文档共同驻留在相同的范围/页面上。它还将使这些文档的索引更有可能完全在内存中。这是因为它更小并且(完全?)更频繁地使用。

如果热门文档与其他文档随机混合,那么在加载文档时您可能不得不在 B-Tree 索引的更多叶元素中出错,因为另一个文档最近加载或访问索引块的概率很小。

2)缩短索引

索引值越短,适合单个 B-Tree 块的值就越多。(注意:键不包含在索引中。)单个存储桶中的条目越多意味着存储桶越少,索引所需的总内存就越少。这意味着块将保留在内存中的概率更高/寿命更长。在您的示例中,减少 20->8 个字符比节省 50% 好。如果您可以将这 8 个字节转换为 long,则可以节省更多,因为 long 没有长度前缀(4 个字节)和尾随 null(总共 5 个字节)。

3) 缩短键名。

字段名称越短,每个文档占用的空间就越少。这具有降低可读性的不幸副作用。

4) 分片

面对整个语料库的读取会耗尽内存和最终的磁盘带宽,这确实是保持性能提高的唯一方法。如果您进行分片,您仍然希望对“热”集合进行分片。

5)将磁盘上的预读调整为一个较小的值。

由于“非热”读取是从磁盘加载随机文档,我们真的只想将该文档以及尽可能少的文档读取/故障到内存中。一旦用户从文件的一部分中读取数据,大多数系统都会尝试并预读一大块数据。这与我们想要的完全相反。

如果您看到系统出现很多故障,但 mongod 进程的常驻内存没有接近系统可用内存,您可能会看到操作系统读取无用数据的影响。

6) 尝试对键使用单调递增的值。

这将触发优化(对于基于 ObjectId 的索引),当索引块拆分时,它将以 90/10 而不是 50/50 执行此操作。结果是索引中的大多数块将接近容量,您将需要更少的块。

如果您事后只知道“热”的 50,000 个文档,那么按索引顺序将它们添加到单独的集合中也会触发此优化。

抢。

于 2013-07-22T01:05:32.310 回答