2017-10-18 101 views
0

我创建了一个复合索引:MongoDB的为什么是一个复合指数包括2dsphere不使用

db.lightningStrikes.createIndex({ datetime: -1, location: "2dsphere" }) 

但是当我运行MongoDB的下面的查询不考虑指数,使得COLLSCAN。

db.lightningStrikes.find({ datetime: { $gte: new Date('2017-10-15T00:00:00Z') } }).explain(true).executionStats 

完整的结果是波纹管:

{ 
    "executionSuccess" : true, 
    "nReturned" : 2, 
    "executionTimeMillis" : 0, 
    "totalKeysExamined" : 0, 
    "totalDocsExamined" : 4, 
    "executionStages" : { 
     "stage" : "COLLSCAN", 
     "filter" : { 
      "datetime" : { 
       "$gte" : ISODate("2017-10-115T00:00:00Z") 
      } 
     }, 
     "nReturned" : 2, 
     "executionTimeMillisEstimate" : 0, 
     "works" : 6, 
     "advanced" : 2, 
     "needTime" : 3, 
     "needYield" : 0, 
     "saveState" : 0, 
     "restoreState" : 0, 
     "isEOF" : 1, 
     "invalidates" : 0, 
     "direction" : "forward", 
     "docsExamined" : 4 
    }, 
    "allPlansExecution" : [ ] 
} 

诗篇。我只插入了4个文档。

为什么会发生?
https://gist.github.com/anonymous/8dc084132016a1dfe0efb150201f04c7

db.lightningStrikes.find({ datetime: { $gte: new Date('2017-10-11T23:59:56Z'), $lte: new Date('2017-10-11T23:59:57Z') } }).hint("datetime_-1_location_2dsphere").explain(true) 

从上面的查询结果:从上面的查询

db.lightningStrikes.find({ datetime: { $gte: new Date('2017-10-11T23:59:56Z'), $lte: new Date('2017-10-11T23:59:57Z') } }).explain(true) 

结果 https://gist.github.com/anonymous/2b76c5a7b4b348ea7206d8b544c7d455

回答

0

为了帮助理解MongoDB是在这里做什么,你可以:

  • [R un explainallPlansExecution mode,看看被拒绝的计划,看看为什么MongoDB拒绝你的索引
  • 运行查找与.hint(_your_index_name_)并比较解释输出与你原来的(非暗示)找到的输出。

这两个都旨在得到同样的东西,即;比较解释(1)使用COLLSCAN找到的计划和(2)使用您的索引的查找计划。通过比较这些解释计划,您可能会看到一些差异,这就解释了MongoDB决定不使用您的索引。

关于分析解释计划的更多细节in the docs

如果您需要帮助确定MongoDB选择COLLSCAN的原因,您甚至可以使用比较计划更新您的OP。

更新1:看你提供的解释计划...

plan使用索引,但在解释计划输出...

 "inputStage" : { 
      "stage" : "IXSCAN", 
      "nReturned" : 4, 
      "executionTimeMillisEstimate" : 0, 
      "works" : 5, 
      "advanced" : 4, 
      ..., 
      "keyPattern" : { 
       "datetime" : -1, 
       "location" : "2dsphere" 
      }, 
      "indexName" : "datetime_-1_location_2dsphere", 
      ..., 
      "indexVersion" : 2, 
      ..., 
      "keysExamined" : 4, 
      ... 
     } 

...表明,它使用该索引检查4个索引键,然后将4个文档返回到FETCH阶段。这告诉我们该索引没有提供任何选择性,选择性由IXSCAN后面的FETCH阶段提供。这实际上是COLLSCAN的功能,但没有多余的IXSCAN。这可能会扩大为什么MongoDB更喜欢COLLSCAN,但为什么IXSCAN无能为力?我怀疑这是因为2dsphere索引不能用于回答在2dsphere字段中缺少地理谓词的查询。您的查询的谓词超过datetime,但没有超过location的地理谓词。我认为这意味着MongoDB不能使用2dsphere索引来回答datetime以上的谓词。有关此背景的更多信息in the docs。简单地说,使用稀疏索引意味着索引中没有必要为集合中的每个文档定义一个条目,因此如果您在没有location属性的情况下进行搜索,那么MongoDB不能依赖索引来满足查询。

您可以测试这种说法是否正确由...

  • 更新您的查询,包括在每个datetimelocation的谓词属性

  • 更新UUR查询包括谓词在location属性只有

...并为每个这些运行查询,然后检查解释计划输出以查看IXSCAN阶段是否实际选择了任何内容。如果IXSCAN阶段是有选择的,那么您应该在解释计划输出中看到钥匙examined > nReturned(假设您传递的标准确实选择了< 4文档!)。

+0

这个数据库只是一个示例,我创建它,因为在生产中我具有相同的结构,它发生的行为相同,但具有数十亿个文档。 当我通过datetime和另一个字段创建复合索引时,但datetime与geospatial不起作用。有点奇怪! 我已经尝试了“提示”,但尽管MongoDB考虑了索引,但实际上它扫描内存中的所有索引,而不是按日期间隔过滤。 我检查了文档,它应该工作。 https://docs.mongodb.com/manual/core/2dsphere/#create-a-compound-index-with-2dsphere-index-key – Michael

+0

我不认为这是这个问题的一般答案,即没有'使用我的索引'在MongoDB中切换:)。所以,任何试图为这个问题提供具体答案的人都需要看比较解释计划。我强烈建议使用[docs](https://docs.mongodb.com/manual/tutorial/analyze-query-plan/)帮助收集这两个计划并自行审查它们以帮助理解解释输出的内容告诉你。 – glytching

+0

我觉得它很奇怪它通过日期时间和另一种类型的字段与复合索引一起使用,并且不适用于日期时间和地理空间字段。无论如何,我会在我的问题上追加“解释”,谁知道帮助确定发生的事情。 – Michael