我需要存储数十亿个小数据结构(每个大约200个字节)。到目前为止,将每个元素存储为单独的文档运行良好,Mongo每秒提供大约10,000个结果。我使用20字节的哈希作为每个文档的_id,以及_id字段的单个索引。在测试中,这适用于包含5,000,000个文档的数据集。
在操作中,我们将每秒发出大约10,000个请求,每秒更新现有文档约1,000次,并且每秒插入新文档可能超过100次。
当我们无法在RAM中存储整个索引时,我们如何管理更大的数据集?如果我们将几个元素组合到每个文档中,MongoDB会表现得更好 - 为了更快地搜索索引,但每个查询中返回的数据更多吗?
与SO上的其他问题不同,我不仅对我们可以填充到Mongo的数据感兴趣。它可以清楚地管理我们正在查看的数据量。我担心的是,在RAM受限的情况下,我们如何才能最大限度地提高find
对大型集合的操作速度。
我们的搜索将倾向于聚集;大约50,000个元素将满足约50%的查询,但剩余的50%将随机分布在所有数据中。我们可以通过将这50%的数据移到他们自己的集合中来获得性能提升,以便将最常用数据的较小索引保持在ram中吗?
将_id字段的大小从20字节减小到8字节会对MnogoDB的索引速度产生重大影响吗?
答案 0 :(得分:23)
我想到了一些策略:
1)为“热门”文档使用不同的集合/数据库。
如果你知道哪些文件在hot set中,那么,是的,将它们移动到一个单独的集合中会有所帮助。这将确保热文档共存于相同的范围/页面上。它还将使这些文档的索引更可能完全在内存中。这是因为它更小并且(完全?)更频繁地使用。
如果热文档随机与其他文档混合,那么在加载文档时,您可能不得不在B-Tree索引的更多叶元素中出错,因为最近加载或访问了索引块的另一个文档的概率很小。
2)缩短索引的值。
索引值越短,适合单个B树块的值越多。 (注意:密钥不包含在索引中。)单个存储桶中的条目越多意味着索引所需的存储桶越少,总内存越少。这意味着块将保留在内存中的概率更高/寿命更长。在您的示例中,20-> 8字符减少比50%节省更好。如果您可以将这8个字节转换为long,则可以节省更多,因为longs没有长度前缀(4个字节)和尾随空值(总共5个字节)。
3)缩短键名。
字段命名越短,每个文档占用的空间越少。 这具有降低可读性的不幸副作用。
4)碎片
这实际上是在整个语料库中读取时保持性能的唯一方法,这会耗尽内存和最终的磁盘带宽。如果你做了碎片,你仍然想要打破'热'集合。
5)Adjust the read-ahead on disk to a small value.
由于'非热'读取正在从磁盘加载随机文档,我们实际上只想读取/故障到文档内存和尽可能少的文档。一旦用户从文件的一部分读取,大多数系统将尝试读取大块数据。这与我们想要的完全相反。
如果您发现系统出现故障但mongod进程的驻留内存未接近系统可用内存,您可能会看到操作系统读取无用数据的影响。
6)尝试使用单调增加键的值。
这将触发优化(对于基于ObjectId的索引),当索引块分割时,它将在90/10而不是50/50处进行。结果是索引中的大多数块都接近容量,您将需要更少的块。
如果您事后只知道'热'50,000文档,那么按索引顺序将它们添加到单独的集合中也会触发此优化。
罗布。