【问题标题】:MongoDB query covered by index but $exists field not contained in the indexMongoDB 查询被索引覆盖,但 $exists 字段未包含在索引中
【发布时间】:2013-10-11 15:47:48
【问题描述】:

我有一个表单集合

{
    "fieldA":"ValueA",
    "fieldB":"ValueB"
}

其中 fieldA 始终存在于文档中,但 fieldB 可能存在也可能不存在于文档中。

我们还假设我在 fieldA 上有一个名为 fieldAIndex 的索引

现在有了这个索引,我希望 fieldAIndex 完全覆盖下面的查询

db.collection.find({"fieldA":"Value1"},{"_id":0,"fieldA":1})

使用 explain() 运行证实了这种情况:

{
    "indexOnly" : true
}

但是当我运行以下查询时令人惊讶:

db.collection.find({"fieldA":"Value1","fieldB":{"$exists":true}},{"_id":0,"fieldA":1})

解释也返回

{
    "indexOnly" : true
}

鉴于 fieldB 不在索引中,查询如何仅从索引中返回?索引是否包含有关存在的字段的信息或解释是否返回不正确?

提前致谢,

马特。

【问题讨论】:

标签: mongodb indexing exists explain


【解决方案1】:

我相信这是 MongoDB 中查询引擎的工作方式。由于您的第一个标准的项目矩阵几乎可以满足所有条件,因此无需再做任何事情。

这里是集合上的索引:

[
{
    "v" : 1,
    "key" : {
        "_id" : 1
    },
    "ns" : "test.colTest",
    "name" : "_id_"
},
{
    "v" : 1,
    "key" : {
        "fieldA" : 1
    },
    "ns" : "test.colTest",
    "name" : "fieldA_1"
}
]

另外,您还没有正确完成研究。尝试将更多文档添加到集合中,您的问题将失败。

db.colTest.insert({fieldA:"1"})

运行查询:

db.colTest.find({"fieldA":"value1","fieldB":{"$exists":true}}).explain()

这是结果

{
"cursor" : "BtreeCursor fieldA_1",
"isMultiKey" : false,
"n" : 1,
"nscannedObjects" : 1,
"nscanned" : 1,
"nscannedObjectsAllPlans" : 1,
"nscannedAllPlans" : 1,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
    "fieldA" : [
        [
            "value1",
            "value1"
        ]
    ]
},
"server" : "local:27017"
}

此外,当您以不同方式查询时,explain() 的结果会再次发生变化。

db.colTest.find({"fieldB":{"$exists":true}, "fieldA":"value1"}).explain()

这是输出:

{
"cursor" : "BtreeCursor fieldA_1",
"isMultiKey" : false,
"n" : 1,
"nscannedObjects" : 1,
"nscanned" : 1,
"nscannedObjectsAllPlans" : 1,
"nscannedAllPlans" : 1,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
    "fieldA" : [
        [
            "value1",
            "value1"
        ]
    ]
},
"server" : "local:27017"
}

请通读文档,这里是参考: http://docs.mongodb.org/manual/reference/method/cursor.explain/

我认为确保使用索引的更可靠方法是查看“n”、“nscanned”和“nscannedObjects”。这些字段将为您提供更清晰的画面。

希望这会有所帮助!

【讨论】:

  • 嗨。非常感谢您的重播。非常感谢您抽出时间为我调查。只是为了澄清-您提供的查询 (db.colTest.find({"fieldB":{"$exists":true}, "fieldA":"value1"}).explain()) 永远不会被覆盖一个索引,因为您省略了投影。 _id 字段不在索引中,因此如果您在查询中返回它,则永远无法覆盖查询。试试 db.colTest.find({"fieldB":{$exists:true},"fieldA":"value1"},{"_id":0,"fieldA":1}).explain()。正如我测试的那样,这应该返回 indexOnly true。谢谢。马特。
【解决方案2】:

出现这种行为是由于在 explain() 中报告 indexOnly 的方式存在问题。它将在 2.5.4 mongodb 版本中修复 (https://jira.mongodb.org/browse/SERVER-5759)。

明确地说,检查索引中不存在的字段不应该在 explain() 中返回 indexOnly=true。任何这样的查询都不会被索引覆盖。

感谢 jeffl 指出这个 mongodb 问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-02-07
    • 1970-01-01
    • 1970-01-01
    • 2016-07-10
    • 2020-10-11
    • 1970-01-01
    • 1970-01-01
    • 2014-08-01
    相关资源
    最近更新 更多