为什么以及何时需要重建 MongoDB 中的索引?

Why and when is necessary to rebuild indexes in MongoDB?

和MongoDB一起工作了一段时间,今天和同事讨论的时候有疑问。

问题在于,当您在 MongoDB 中创建索引时,会处理集合并构建索引。

索引在文档的插入和删除中更新,所以我真的不认为需要 运行 重建索引操作(删除索引然后重建它)。

根据 MongoDB 文档:

Normally, MongoDB compacts indexes during routine updates. For most users, the reIndex command is unnecessary. However, it may be worth running if the collection size has changed significantly or if the indexes are consuming a disproportionate amount of disk space.

是否有人需要 运行值得重建索引的操作?

虽然我不知道确切的技术原因,但在 MongoDB 中,我可以根据我对其他系统索引的了解以及您引用的文档对此做出一些假设.

索引的总体思路

当从一个文档移动到下一个文档时,在整个文档集合中,跳过所有不需要处理的数据会浪费很多时间和精力。如果您要查找 ID 为“1234”的文档,则必须遍历每个文档的 100K+ 会使速度变慢

不必搜索集合中每个文档的所有内容(物理移动磁盘读头等),索引可以加快搜索速度。它基本上是一个 key/value 对,为您提供该文档的 ID 和位置。 MongoDB 可以快速扫描索引中的所有 id,找到它需要的文档的位置,然后直接加载它们。

为索引分配文件大小

索引占用磁盘 space 因为它们基本上是 key/value 对存储在一个更小的位置。如果您有一个非常大的集合(集合中的大量项目),那么您的索引的大小会增加。

大多数操作系统以特定的块大小分配磁盘块 space。大多数数据库还根据需要以大块分配磁盘 space。

添加 100K 文档时文件大小不会增加 100K,MongoDB 可能会增加 1MB 或 10MB 或其他大小 - 我不知道实际增长大小是多少。在 SQL Server 中,你可以告诉它增长的速度有多快,而 MongoDB 可能有类似的东西。

分块增长使 'grow' 文档能够更快地 space ,因为数据库不需要不断扩展。如果数据库现在已经分配了 10MB 的 space,它可以只使用那 space。它不必为每个文档不断扩展文件。它只需要将数据写入文件。

这可能适用于集合和集合索引 - 存储在磁盘上的任何内容。

文件大小和索引重建

当大型集合添加和删除大量文档时,索引会变得碎片化。索引键可能没有顺序,因为在索引文件的中间有空间,而不是在末尾,当需要建立索引时。索引键之间也可能有很多 space。

如果索引中有10,000条,需要插入#10,001,可以插入到索引文件的中间。现在,索引需要自行重建以使一切恢复正常。这涉及移动大量数据,以便在文件末尾腾出空间并将项目 #10,001 放在末尾。

如果索引经常被破坏——大量的东西被删除和添加——增加索引文件的大​​小并总是把东西放在最后可能会更快。这可以快速创建索引,但会在删除旧内容的文件中留下空洞。

如果索引文件在以前被删除的地方有空space,这在读取索引时是浪费精力。索引文件比需要移动更多,以到达索引中的下一个项目。因此,索引会自行修复...对于非常大的集合或对集合进行非常大的更改可能会很耗时。

为大型索引文件重建

可能需要大量的磁盘访问和 I/O 操作才能正确地将索引文件压缩回合理的大小,并且一切都井井有条。将不合适的项目移到临时位置,在正确的位置释放 space,然后将它们移回。哦对了,要释放 space,您必须将其他项目移动到临时位置。它是递归的和笨拙的。

因此,如果您的集合中有大量项目并且该集合定期添加和删除项目,则可能需要从头开始重建索引。这样做会擦除当前索引文件并从头开始重建——这可能比尝试在现有文件中执行数千次移动要快。它不是四处移动,而是从头开始按顺序写入它们。

集合大小的大变化

考虑到我上面的所有假设,集合大小的巨大变化会导致这种颠簸。如果您的集合中有 10,000 个文档,您删除了其中的 8,000 个...好吧,现在您的索引文件中有空的 space,而 8,000 个项目曾经是。 MongoDB 需要移动物理文件中剩余的 2,000 个项目,以紧凑的形式重建它。

与其等待 8,000 个空的 space 被清理,不如从头开始重建剩余的 2,000 个项目可能更快。

结论?也许吧?

因此,您引用的文档可能会处理 "big data" 需求或高抖动的集合和索引。

另外请记住,我是根据我对索引、磁盘分配、文件碎片等的了解做出有根据的猜测

我的猜测是文档中的 "most users" 意味着 99.9% 或更多的 mongodb 集合不需要担心这个。

MongoDB具体案例

根据 MongoDB 文档:

The remove() method does not remove the indexes

因此,如果您从集合中删除文档,您就是在浪费磁盘 space,除非您为该集合重建索引。

根据 MongoDB 文档,通常不需要定期重建索引。

注意:关于存储的任何建议在 MongoDB 3.0+ 中变得更加有趣,它引入了 pluggable storage engine API。我下面的评论专门针对 MongoDB 3.0 及更早版本中的默认 MMAP 存储引擎。 WiredTiger 和其他存储引擎对数据和索引有不同的存储实现。

在以下情况下,使用 MMAP 存储引擎重建索引可能会有一些好处:

  • 与数据相比,索引消耗的 space 量大于预期。注意:您需要监控历史数据和索引大小以获得比较基准。

  • 您想从旧索引格式迁移到新索引格式。如果建议重建索引,这将在升级说明中提及。例如,MongoDB 2.0 引入了重要的 index performance improvements so the release notes include a suggested reindex to the v2.0 format after upgrading. Similarly, MongoDB 2.6 introduced 2dsphere (v2.0) indexes,它具有不同的默认行为(默认为稀疏)。索引版本升级后不重建现有索引; if/when升级的选择留给数据库管理员。

  • 您已将集合的 _id 格式更改为单调递增键(例如 ObjectID)或从单调递增键(例如 ObjectID)更改为随机值。这有点深奥,但是有一个索引优化可以将 b 树桶拆分为 90/10(而不是 50/50),如果您插入的 _ids 总是在增加(参考:SERVER-983) .如果您的 _id 的性质发生显着变化,则可以使用重新索引构建更高效的 b 树。

有关一般 B 树行为的更多信息,请参阅:Wikipedia: B-tree

可视化索引使用情况

如果您真的很想深入了解索引的内部结构,可以尝试一些实验性的 commands/tools。我希望这些仅限于 MongoDB 2.4 和 2.6: