Mongodb Mongo在使用match+排序操作进行聚合期间使用了错误的索引

Mongodb Mongo在使用match+排序操作进行聚合期间使用了错误的索引,mongodb,indexing,aggregation-framework,Mongodb,Indexing,Aggregation Framework,我使用的是MongoDB版本4.2.0。我有一个具有以下索引的集合: {uuid:1}, {唯一:true,名称:uuid_idx} 及 {field1:1,field2:1,_id:1}, {唯一:true,名称:component_idx} 执行此查询时 聚合[ {$match:{uuid:} ] 规划器正确选择uuid_idx 添加此排序子句时 聚合[ {$match:{uuid:}}, {$sort:{field1:1,field2:1,_id:1} ] 规划器选择component_i

我使用的是MongoDB版本4.2.0。我有一个具有以下索引的集合:

{uuid:1}, {唯一:true,名称:uuid_idx} 及

{field1:1,field2:1,_id:1}, {唯一:true,名称:component_idx} 执行此查询时

聚合[ {$match:{uuid:} ] 规划器正确选择uuid_idx

添加此排序子句时

聚合[ {$match:{uuid:}}, {$sort:{field1:1,field2:1,_id:1} ] 规划器选择component_idx,这会使查询速度变慢

我希望sort子句在这种情况下不会有什么不同。为什么Mongo在这两种情况下都不使用uuid_idx索引

编辑: 稍微澄清一下,我知道使用正确的索引有一些变通方法,但我正在寻找一个解释,解释为什么这不会自动发生,如果可能的话,与官方文档的链接。谢谢

为什么会这样

让我们了解Mongo如何选择要使用的索引

如果一个查询可以由多个索引来满足,那么由于Mongo实际上选择了集合中定义的所有可能相关的索引,所以“满足”将被丢失

然后,MongoDB将并行测试所有适用的索引。查询计划器将选择第一个可以返回101个结果的索引

这意味着对于特定的查询,该索引实际上获胜

我们能做什么

我们可以使用,提示基本上强制Mongo使用特定的索引,但是不建议使用Mongo,因为如果发生更改,Mongo将无法适应这些更改。

查询:

aggregate( 
  [
    { $match : { uuid : "some_value" } },
    { $sort : { fld1: 1, fld2: 1, _id: 1 } }
  ],
)
不使用索引uuid_idx

对于在匹配和排序操作中使用索引,您可以使用两个选项:

1定义一个新的复合索引:{uuid:1,fld1:1,fld2:1,_id:1}

match和match+排序查询都将使用此索引进行匹配和排序操作

aggregate( 
  [
    { $match : { uuid : "some_value" } },
    { $sort : { fld1: 1, fld2: 1, _id: 1 } }
  ],
  { hint: "uuid_idx"}
)
2使用现有索引对uuid索引进行提示

match和match+排序查询都将使用此索引进行匹配和排序操作

aggregate( 
  [
    { $match : { uuid : "some_value" } },
    { $sort : { fld1: 1, fld2: 1, _id: 1 } }
  ],
  { hint: "uuid_idx"}
)

如果有人想知道,查询是动态生成的,当前自动插入sort子句。第二个聚合查询选择了多少文档,其中包含匹配和排序阶段?谢谢您的回答,但我仍然感到困惑。您的第一个链接涉及版本2.6,我找不到版本4.2的相同解释:它仍然适用吗?此外,从该链接看,所选索引要么返回所有匹配的结果,要么比所有其他索引更快返回101个结果。可能是uuid_idx返回一个匹配比复合_idx返回101个匹配慢吗?更新链接:你是说即使match子句上有一个100%选择性的索引,计划者也总是优先考虑排序子句上的索引吗?官方文档中是否有关于此行为的参考?没有,排序操作没有这样的优先级。一般来说,在同一个查询上使用两个索引不是最佳做法;如果查询可以使用一个复合索引进行匹配和排序操作,那么这是最好的选择。查询优化器基于可用和可行的索引(也称为候选索引)生成多个计划。MongoDB使用基于观察或经验的经验查询优化器。每个候选计划都会在短时间内执行。优化器可以看到哪个计划在这段时间内执行得最好。最佳计划由各种因素决定,如最快的速度、更多的文档,甚至一个计划可能在试用期间完成、阈值等。。另外,请参见。我尝试了以下查询,发现它使用的是uuid_idx,而不是聚合中的复合索引:db.colln.find{uuid:}.sort{fld1:1,fld2:1,_id:1}。排序在内存中进行。但是,当对find.sort查询应用四个字段的复合索引时,两个操作都使用索引。