Mongo没有使用索引

时间:2017-01-17 22:59:25

标签: mongodb mongodb-query

我在集合中有以下索引:

db.JobStatusModel.getIndexes()
[
    {
        "v" : 1,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_",
        "ns" : "jobs.JobStatusModel"
    },
    {
        "v" : 1,
        "key" : {
            "peopleId" : 1,
            "jobId" : 1
        },
        "name" : "peopleId_jobId_compounded",
        "ns" : "jobs.JobStatusModel"
    },
    {
        "v" : 1,
        "key" : {
            "jobId" : 1
        },
        "name" : "jobId_1",
        "ns" : "jobs.JobStatusModel",
        "background" : true
    },
    {
        "v" : 1,
        "key" : {
            "peopleId" : 1,
            "disInterested" : 1
        },
        "name" : "peopleId_1_disInterested_1",
        "ns" : "jobs.JobStatusModel",
        "background" : true
    }
]

尝试计算针对复合索引运行的一些运行缓慢的查询,但是,即使是简单的查询也没有使用索引:

db.JobStatusModel.find({ jobId : '1f940601ff7385931ec04dca88c853dd' }).explain(true)
{
    "cursor" : "BtreeCursor jobId_1",
    "isMultiKey" : false,
    "n" : 221,
    "nscannedObjects" : 221,
    "nscanned" : 221,
    "nscannedObjectsAllPlans" : 221,
    "nscannedAllPlans" : 221,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 1,
    "nChunkSkips" : 0,
    "millis" : 1,
    "indexBounds" : {
        "jobId" : [
            [
                "1f940601ff7385931ec04dca88c853dd",
                "1f940601ff7385931ec04dca88c853dd"
            ]
        ]
    },
    "allPlans" : [
        {
            "cursor" : "BtreeCursor jobId_1",
            "isMultiKey" : false,
            "n" : 221,
            "nscannedObjects" : 221,
            "nscanned" : 221,
            "scanAndOrder" : false,
            "indexOnly" : false,
            "nChunkSkips" : 0,
            "indexBounds" : {
                "jobId" : [
                    [
                        "1f940601ff7385931ec04dca88c853dd",
                        "1f940601ff7385931ec04dca88c853dd"
                    ]
                ]
            }
        }
    ],
    "server" : "mongo3.pilot.dice.com:27017",
    "filterSet" : false,
    "stats" : {
        "type" : "FETCH",
        "works" : 222,
        "yields" : 1,
        "unyields" : 1,
        "invalidates" : 0,
        "advanced" : 221,
        "needTime" : 0,
        "needFetch" : 0,
        "isEOF" : 1,
        "alreadyHasObj" : 0,
        "forcedFetches" : 0,
        "matchTested" : 0,
        "children" : [
            {
                "type" : "IXSCAN",
                "works" : 222,
                "yields" : 1,
                "unyields" : 1,
                "invalidates" : 0,
                "advanced" : 221,
                "needTime" : 0,
                "needFetch" : 0,
                "isEOF" : 1,
                "keyPattern" : "{ jobId: 1.0 }",
                "isMultiKey" : 0,
                "boundsVerbose" : "field #0['jobId']: [\"1f940601ff7385931ec04dca88c853dd\", \"1f940601ff7385931ec04dca88c853dd\"]",
                "yieldMovedCursor" : 0,
                "dupsTested" : 0,
                "dupsDropped" : 0,
                "seenInvalidated" : 0,
                "matchTested" : 0,
                "keysExamined" : 221,
                "children" : [ ]
            }
        ]
    }
}

正如我们从输出中看到的那样,我从输出中得到"indexOnly" : false,意味着即使我的字段被索引,它也不能只进行索引扫描。如何确保查询仅针对索引运行?

2 个答案:

答案 0 :(得分:3)

  

即使是简单的查询也没有使用索引:

您的查询 使用IXSCAN阶段和索引光标("cursor" : "BtreeCursor jobId_1",)所指示的索引。

  

尝试计算针对复合索引运行的一些运行缓慢的查询,但是,

根据提供的getIndexes()输出,您对单个字段jobId的查询只有一个要考虑的候选索引:{jobId:1}。此查询以1毫秒("millis" : 1)运行并返回221个文档,查看221个索引键 - 对于匹配项的关键比较,这是一个理想的1:1命中率。

如果您还在查询中提供了{peopleId:1, jobId:1}值,则只会考虑peopleId的复合索引。但是,如果您有时仅在jobId上查询,而且经常在peopleIdjobId上进行查询,则可能会以相反的顺序创建包含这些字段的复合索引。 {jobId:1, peopleId:1}上的复合索引可以消除{jobId:1}索引的需要,因为它可以满足相同的查询。

有关详细信息,请参阅MongoDB手册中的Create Indexes to Support Your QueriesOptimizing MongoDB Compound Indexes博文。

注意:您还没有提到您正在使用的MongoDB服务器版本,但explain()输出的格式表明您正在运行已达到使用寿命的旧版MongoDB(即截至2017年1月的任何比MongoDB 3.0更早的版本。我强烈建议升级到更新且受支持的版本(例如MongoDB 3.2或3.4),因为有显着的改进。生命周期服务器发布系列不再维护,可能会使您的应用程序暴露于后续生产版本中已解决的已知错误和漏洞。

  

正如我们从输出中看到的那样,我从输出中得到"indexOnly" : false,意味着即使我的字段被索引,它也不能只进行索引扫描。如何确保查询仅针对索引运行?

covered query的特殊情况下,indexOnly值仅为true。覆盖查询是查询中的所有字段都是索引的一部分结果中的所有字段都在同一索引中的查询。通常不包括索引查询:索引查找用于查找匹配的文档,然后检索这些文档并将其过滤到查询投影中请求的字段。

答案 1 :(得分:1)

为了确保您获得indexOnly,您只需要从索引中返回这些字段,请使用projection

db.collection.find( <query filter>, <projection> )

db.JobStatusModel.find({ jobId : '1f940601ff7385931ec04dca88c853dd' }, {jobId:1, _id:0})