在MongoDB中快速搜索数十亿个小文档的策略

Nei*_*eil 19 search scalability mongodb database-performance pymongo

我需要存储数十亿个小数据结构(每个大约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的索引速度产生重大影响吗?

Rob*_*ore 24

我想到了一些策略:

1)为"热门"文档使用不同的集合/数据库.

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

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

2)缩短索引.

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

3)缩短键名.

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

4)碎片

对于耗尽内存和最终磁盘带宽的整个语料库中的读取,这实际上是保持性能提升的唯一方法.如果你做了碎片,你仍然想要打破"热"的收藏品.

5)将磁盘上的预读调整为较小的值.

由于'非热'读取正在从磁盘加载随机文档,我们实际上只想读取/故障到文档的内存和尽可能少的文档.一旦用户从文件的一部分读取,大多数系统将尝试读取大块数据.这与我们想要的完全相反.

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

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

这将触发优化(对于基于ObjectId的索引),当索引块分割时,它将在90/10而不是50/50处这样做.结果是索引中的大多数块都接近容量,您将需要更少的块.

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

抢.