mongodb - 为什么mongodb不使用全索引

标签 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]"
                    ]
                }

最佳答案

基于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 是 - 只要索引字段中只有一个包含数组值(在我的情况下是这样),索引就可以。嵌套级别并不重要。由于需要笛卡尔积,问题确实是并行数组。

关于mongodb - 为什么mongodb不使用全索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47253947/

相关文章:

node.js - Ember、Ember 数据、MongoDB _id 和命名空间

c# - 422 错误 : Python POST Request

c# - 如何在 Mongo 文档中查询字典?

node.js - 使用 NodeJS 重构 mongoose 集合模型

indexing - MongoDB - 当嵌入键是 URI 时索引嵌入键

mongodb - MGO TTL 索引创建以选择性地删除文档

mongodb - 如何正确创建索引mongodb?

mongodb - Mongo 唯一索引不区分大小写

MongoDB:在集合中的数百万条记录上查找 count() 命令的执行时间?

mongodb - MongoDB 中的数组交集