为什么mongodb没有使用完整索引

时间:2017-11-12 21:03:19

标签: mongodb mongodb-query mongodb-indexes

我有一个包含一个4键复合索引的集合:

> db.event.getIndexes()
[
    {
        "v" : 2,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_",
    },
    {
        "v" : 2,
        "key" : {
            "epochWID" : 1,
            "category" : 1,
            "mos.types" : 1,
            "mos.name" : 1
        },
        "name" : "epochWID_category_motype_movalue",
    }
]

查询如下:

> db.event.explain().find({ "epochWID": 1510456188087, "category": 6, "mos.types": 9, "mos.name": "ctx_1" })
{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "indexFilterSet" : false,
        "parsedQuery" : {
            "$and" : [
                {
                    "category" : {
                        "$eq" : 6
                    }
                },
                {
                    "epochWID" : {
                        "$eq" : 1510456188087
                    }
                },
                {
                    "mos.name" : {
                        "$eq" : "ctx_1"
                    }
                },
                {
                    "mos.types" : {
                        "$eq" : 9
                    }
                }
            ]
        },
        "winningPlan" : {
            "stage" : "FETCH",
            "filter" : {
                "mos.name" : {
                    "$eq" : "ctx_1"
                }
            },
            "inputStage" : {
                "stage" : "IXSCAN",
                "keyPattern" : {
                    "epochWID" : 1,
                    "category" : 1,
                    "mos.types" : 1,
                    "mos.name" : 1
                },
                "indexName" : "epochWID_category_motype_movalue",
                "isMultiKey" : true,
                "multiKeyPaths" : {
                    "epochWID" : [ ],
                    "category" : [ ],
                    "mos.types" : [
                        "mos",
                        "mos.types"
                    ],
                    "mos.name" : [
                        "mos"
                    ]
                },
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 2,
                "direction" : "forward",
                "indexBounds" : {
                    "epochWID" : [
                        "[1510456188087.0, 1510456188087.0]"
                    ],
                    "category" : [
                        "[6.0, 6.0]"
                    ],
                    "mos.types" : [
                        "[9.0, 9.0]"
                    ],
                    "mos.name" : [
                        "[MinKey, MaxKey]"
                    ]
                }
            }
        },
        "rejectedPlans" : [ ]
    },
    "serverInfo" : {
        "version" : "3.4.9",
    },
    "ok" : 1
}

现在,如果你看一下该计划的indexBounds:它使用前3个键而不是第4个mos.name,为什么?

                "indexBounds" : {
                    "epochWID" : [
                        "[1510456188087.0, 1510456188087.0]"
                    ],
                    "category" : [
                        "[6.0, 6.0]"
                    ],
                    "mos.types" : [
                        "[9.0, 9.0]"
                    ],
                    "mos.name" : [
                        "[MinKey, MaxKey]"
                    ]
                }

2 个答案:

答案 0 :(得分:1)

多键索引不能跨文档中的多个数组。请参阅文档https://docs.mongodb.com/manual/core/index-multikey/#compound-multikey-indexes

中的限制和推理

答案 1 :(得分:0)

基于https://docs.mongodb.com/manual/core/index-multikey/#compound-multikey-indexes我们需要使用$ elemMatch,因此以下查询使用完整索引

> db.event.explain().find({ "epochWID": 1510456188087, "category": 6, "mos": { $elemMatch: {"types": 9, "name": "ctx_1"} } })
{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "indexFilterSet" : false,
        "parsedQuery" : {
            "$and" : [
                {
                    "mos" : {
                        "$elemMatch" : {
                            "$and" : [
                                {
                                    "name" : {
                                        "$eq" : "ctx_1"
                                    }
                                },
                                {
                                    "types" : {
                                        "$eq" : 9
                                    }
                                }
                            ]
                        }
                    }
                },
                {
                    "category" : {
                        "$eq" : 6
                    }
                },
                {
                    "epochWID" : {
                        "$eq" : 1510456188087
                    }
                }
            ]
        },
        "winningPlan" : {
            "stage" : "FETCH",
            "filter" : {
                "mos" : {
                    "$elemMatch" : {
                        "$and" : [
                            {
                                "types" : {
                                    "$eq" : 9
                                }
                            },
                            {
                                "name" : {
                                    "$eq" : "ctx_1"
                                }
                            }
                        ]
                    }
                }
            },
            "inputStage" : {
                "stage" : "IXSCAN",
                "keyPattern" : {
                    "epochWID" : 1,
                    "category" : 1,
                    "mos.types" : 1,
                    "mos.name" : 1
                },
                "indexName" : "epochWID_category_motype_movalue",
                "isMultiKey" : true,
                "multiKeyPaths" : {
                    "epochWID" : [ ],
                    "category" : [ ],
                    "mos.types" : [
                        "mos",
                        "mos.types"
                    ],
                    "mos.name" : [
                        "mos"
                    ]
                },
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 2,
                "direction" : "forward",
                "indexBounds" : {
                    "epochWID" : [
                        "[1510456188087.0, 1510456188087.0]"
                    ],
                    "category" : [
                        "[6.0, 6.0]"
                    ],
                    "mos.types" : [
                        "[9.0, 9.0]"
                    ],
                    "mos.name" : [
                        "[\"ctx_1\", \"ctx_1\"]"
                    ]
                }
            }
        },
        "rejectedPlans" : [ ]
    },
    "serverInfo" : {
        "version" : "3.4.9",
    },
    "ok" : 1
}
编辑:我联系了MongoDb支持。关于多键索引和数组字段 - tl; dr is - 只要其中一个索引字段包含数组值(在我的情况下为true),索引就可以了。嵌套级别并不重要。由于需要笛卡尔积,问题确实是并行阵列。