为什么Mongodb除非明确提供,否则不会使用嵌套字段索引进行过滤

时间:2018-08-20 19:42:44

标签: mongodb

我发现,如果索引位于嵌套字段上并且根字段用于查询,则mongodb不会使用索引来完成查询。

// create test collection with index on nested field
> db.test.createIndex({ 'nested.a': 1 })
{
        "createdCollectionAutomatically" : true,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "ok" : 1
}

如果仅通过nested字段进行查询,即使包含索引字段,它也会进行列扫描而不使用索引。

> db.test.find({ nested: { $eq: { a: "" } } }).explain()
{
        "queryPlanner" : {
                "plannerVersion" : 1,
                "namespace" : "TestServer.test",
                "indexFilterSet" : false,
                "parsedQuery" : {
                        "nested" : {
                                "$eq" : {
                                        "a" : ""
                                }
                        }
                },
                "winningPlan" : {
                        "stage" : "COLLSCAN",
                        "filter" : {
                                "nested" : {
                                        "$eq" : {
                                                "a" : ""
                                        }
                                }
                        },
                        "direction" : "forward"
                },
                "rejectedPlans" : [ ]
        },
        "serverInfo" : {
                "host" : "caa1852655c1",
                "port" : 27017,
                "version" : "3.6.3",
                "gitVersion" : "9586e557d54ef70f9ca4b43c26892cd55257e1a5"
        },
        "ok" : 1
}

我也可以通过显式提供索引字段来解决此问题:

//               vvvvvvvvvvvvvv explicitly included
> db.test.find({ 'nested.a': "", nested: { $eq: { a: "" } } }).explain()
{
        "queryPlanner" : {
                "plannerVersion" : 1,
                "namespace" : "TestServer.test",
                "indexFilterSet" : false,
                "parsedQuery" : {
                        "$and" : [
                                {
                                        "nested" : {
                                                "$eq" : {
                                                        "a" : ""
                                                }
                                        }
                                },
                                {
                                        "nested.a" : {
                                                "$eq" : ""
                                        }
                                }
                        ]
                },
                "winningPlan" : {
                        "stage" : "FETCH",
                        "filter" : {
                                "nested" : {
                                        "$eq" : {
                                                "a" : ""
                                        }
                                }
                        },
                        "inputStage" : {
                                "stage" : "IXSCAN",
                                "keyPattern" : {
                                        "nested.a" : 1
                                },
                                "indexName" : "nested.a_1",
                                "isMultiKey" : false,
                                "multiKeyPaths" : {
                                        "nested.a" : [ ]
                                },
                                "isUnique" : false,
                                "isSparse" : false,
                                "isPartial" : false,
                                "indexVersion" : 2,
                                "direction" : "forward",
                                "indexBounds" : {
                                        "nested.a" : [
                                                "[\"\", \"\"]"
                                        ]
                                }
                        }
                },
                "rejectedPlans" : [ ]
        },
        "serverInfo" : {
                "host" : "caa1852655c1",
                "port" : 27017,
                "version" : "3.6.3",
                "gitVersion" : "9586e557d54ef70f9ca4b43c26892cd55257e1a5"
        },
        "ok" : 1
}

但是我质疑为什么这是必须的.​​..在我的实际用例中,嵌套字段不仅包含索引字段,而且还需要完整的相等性检查,但是我宁愿不必在以下情况下显式提供索引字段(我觉得)mongodb应该能够从原始查询中推断出索引。

mongodb无法像我期望的那样推断出正确的索引吗?是否只是由于疏忽而未进行优化?我正在运行3.6.3版,4.0或管道中是否有任何改进?还是有更好的方法来处理这种情况?

编辑:我从this question和我自己的实验中发现,它将对$elemMatch查询使用索引。但是我的顶级字段不是数组,所以我不能使用它。嵌套索引是否始终假设顶级字段是数组?有没有办法让它成为我想要的?

0 个答案:

没有答案