首页 > 解决方案 > 未使用MongoDB复合索引

问题描述

我有一个包含近 100k 个文档的 mongodb 索引。在每个文档上,有以下 3 个字段。

arrayX:[ObjectId] someID:ObjectId 时间戳:日期

我按该顺序为 3 个字段创建了复合索引。

当我尝试然后触发聚合查询(用伪代码写在下面)时,如

match(
  and(
    arrayX: (elematch: A),
    someId: Y
  )
)
sort (timestamp: 1)

它最终不会使用复合索引。

我知道的方式是,当我使用时.explain(),winningPlan 阶段是FETCHinputStageisIXSCANindexnameis timestamp_1 ,这意味着它只使用我为时间戳字段创建的另一个单键索引。

有趣的是,如果我删除排序阶段,并保持一切完全相同,mongodb 最终会使用复合索引。

是什么赋予了?

标签: mongodbmongodb-queryaggregation-framework

解决方案


多键索引对排序没有用处。我希望使用其他索引的计划列在拒绝计划中。

如果您使用 allPlansExecution 选项运行说明,则响应还将显示每个计划的执行时间等。

由于多键索引不能用于对结果进行排序,因此该计划将需要阻塞排序阶段。这意味着必须检索所有匹配的文档,然后在发送响应之前在内存中进行排序。

另一方面,使用 timestamp_1 索引意味着在遍历索引时会以预先排序的顺序遇到文档。这里的权衡是没有阻塞排序阶段,但必须检查每个文档以查看它是否与查询匹配。

对于不是很大的数据集,或者当查询将匹配集合的很大一部分时,没有阻塞排序的计划将更快地返回结果。

您可以测试创建另一个索引,{ someID:1, timestamp:1 }因为这可能会减少扫描的文档数量,同时仍然避免阻塞排序。

删除排序阶段时选择复合索引的原因是该阶段可能占执行时间的大部分。

解释输出的 executionStats 部分中的字段在解释结果中进行了解释。比较每个阶段的估计执行时间可以帮助您确定可以调整查询的位置。


推荐阅读