MongoDB为什么不使用包含2dsphere的复合索引

MongoDB为什么不使用包含2dsphere的复合索引,mongodb,indexing,mongodb-query,Mongodb,Indexing,Mongodb Query,我创建了一个复合索引: db.lightningStrikes.createIndex({ datetime: -1, location: "2dsphere" }) 但是,当我运行下面的查询时,MangGDB不考虑索引,生成CORSCAN。< /P> db.lightningStrikes.find({ datetime: { $gte: new Date('2017-10-15T00:00:00Z') } }).explain(true).executionStats 全部结果如下: {

我创建了一个复合索引:

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

但是,当我运行下面的查询时,MangGDB不考虑索引,生成CORSCAN。< /P>

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份文件

为什么会这样

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

以上查询结果:

要了解MongoDB在这里做什么,您可以:

  • 使用运行
    explain
    ,查看被拒绝的计划,了解MongoDB拒绝索引的原因
  • 使用
    .hint(\u您的索引\u名称)
    运行查找,并将解释输出与原始(非提示)查找的输出进行比较
这两者都是为了达到同一目的,即;比较解释(1)使用COLLSCAN的查找计划和(2)使用索引的查找计划。通过比较这些解释计划,您可能会看到一些差异,这解释了MongoDB决定不使用索引的原因

有关分析和解释计划的更多详细信息

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

更新1:查看您提供的解释计划

这使用您的索引,但解释计划输出

        "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个文档返回到获取阶段。这告诉我们索引没有提供任何选择性,选择性是由IXSCAN之后的FETCH阶段提供的。这实际上是COLLSCAN所做的,但没有冗余的IXSCAN。这也许可以解释为什么MongoDB更喜欢COLLSCAN,但为什么IXSCAN什么都不做?我怀疑这是因为2dsphere索引不能用于回答在2dsphere字段上缺少地理谓词的查询。您的查询在
日期时间
上有一个谓词,但在
位置
上没有地理谓词。我认为这意味着MongoDB不能使用2dsphere索引来回答
datetime
上的谓词。更多关于这方面背景的信息。简要地;使用稀疏索引意味着集合中的每个文档的索引中不一定都有一个条目,因此如果搜索时没有
location
属性,则MongoDB无法依赖索引来满足查询

您可以通过以下方式测试此断言是否正确

  • 更新查询以在每个
    datetime
    location
    属性上包含谓词

  • 更新uur查询以仅在
    位置上包含谓词


。。。对于其中的每一个,运行查询,然后检查解释计划输出,以查看IXSCAN阶段是否实际选择了任何内容。如果IXSCAN阶段是选择性的,那么您应该在解释计划输出中看到键
inspected>nReturned
(假设您传入的标准确实选择了<4个文档!)。

此数据库只是一个示例,我创建它是因为在生产中我有相同的结构,并且它发生相同的行为,但是有几十亿的文件。当我通过datetime和另一个字段创建复合索引时,它可以工作,但datetime和geospatial不能工作。真奇怪!我已经尝试过“提示”,但是尽管MangGDB考虑了索引,但实际上它扫描了内存中的所有索引,而不是按日期间隔进行过滤。我签入了文档,它应该可以工作。我不认为这个问题有一个通用的答案,即MongoDB中没有“使用我的索引”开关:)。因此,任何试图为这个问题提供具体答案的人都需要查看比较解释计划。我强烈建议您收集这两个计划,并亲自检查它们,使用它来帮助您理解解释输出告诉您的内容。我认为它适用于按日期时间和其他类型的字段的复合索引,而不适用于日期时间和地理空间字段。无论如何,我会在我的问题上加上“解释”,谁知道有助于确定发生了什么。@Michael我已经根据您提供的解释计划更新了答案,并提供了一些反馈。您的答案非常完美!我只通过“datetime”创建了一个额外的索引来解决这个问题。你可能喜欢看这个链接:非常感谢!
        "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,
            ...
        }