如何快速插入到一个非常大的集合

Vai*_*hek 3 mongodb

我收集了超过 7000 万份文件。每当我批量添加新文档(比如 2K)时,插入操作真的很慢。我怀疑这是因为 mongo 引擎正在将所有新文档的 _id 与所有 7000 万个进行比较,以找出任何 _id 重复条目。由于基于 _id 的索引是磁盘驻留的,它会使代码变慢。

有没有办法避免这种情况。我只希望 mongo 获取新文档并按原样插入,而不进行此检查。甚至有可能吗?

Ste*_*nie 6

诊断“慢”性能

您的问题包括许多关于 MongoDB 如何工作的主要假设。我将在下面解决这些问题,但我建议您尝试根据数据库指标(即serverStatusmongostatmongotop)、系统资源监控和 MongoDB 日志中慢查询信息等事实来理解任何性能问题。指标需要随着时间的推移进行监控,以便您可以确定部署的“正常”情况,因此我强烈建议使用特定于 MongoDB 的监控工具,例如MMS Monitoring

一些有趣的演示文稿为性能故障排除和调试提供了非常相关的背景材料:

提高刀片效率

除了了解实际性能挑战所在并调整部署之外,您还可以通过以下方式提高插入效率:

  • 删除此集合上任何未使用或冗余的二级索引

  • 使用Bulk API批量插入文档

评估假设

每当我批量添加新文档(比如 2K)时,插入操作真的很慢。我怀疑这是因为 mongo 引擎正在将所有新文档的 _id 与所有 7000 万个进行比较,以找出任何 _id 重复条目。由于基于 _id 的索引是磁盘驻留的,它会使代码变慢。

如果一个集合有 7000 万个条目,这并不意味着索引查找涉及 7000 万次比较。索引值存储在允许少量有效比较的B 树中。确切的数字将取决于树的深度以及索引的构建方式以及您正在查找的值……但将在 10 次(而不是数百万次)比较的数量级上。

如果您真的对内部结构感到好奇,您可以在开发环境中启用一些实验性存储和索引统计信息:Storage-viz: Storage Visualizers and Commands for MongoDB

由于基于 _id 的索引是磁盘驻留的,它会使代码变慢。

MongoDB 将您的工作集(最近访问的数据和索引条目的一部分)加载到可用内存中。

如果您能够以大致升序创建 id(例如,生成的 ObjectId),那么所有更新都将发生在 B 树的右侧,并且您的工作集将小得多(常见问题解答:“必须是我的工作集适合 RAM" )。

是的,我可以让 mongo 自己使用 _id,但我不想浪费一个非常好的索引。此外,即使我让 mongo 为自己生成 _id 是否仍然需要比较重复的键错误?

_idMongoDB 中的所有文档都需要唯一的。默认值ObjectId是基于应确保唯一性的公式生成的(即,返回重复键异常的可能性极低,因此您的应用程序不会得到重复键异常,而必须使用 new 重试_id)。

如果您对_id文档中的唯一性有更好的候选者,那么请随意使用此字段(或字段集合),而不是依赖于生成的_id. 请注意,_id是不可变的,因此您不应使用稍后可能要修改的任何字段。