首页 > 解决方案 > MongoDB:查询多个字段和索引

问题描述

我通过猫鼬使用 MongoDB。

  1. 当您使用非索引字段查询索引字段时会发生什么?请参阅下面的代码。

    // For example
    MyModel.find({ _id: '123', name: 'Jina'});
    

    MongoDB 是否进行集合扫描或索引是否有助于提高查询效率?查询与仅使用该_id字段有什么不同吗?

  2. 如果 MongoDB 在您查询非索引字段时进行集合扫描。如果集合扫描完全一样,查询多个非索引字段是否会加快查询速度?假设我查询五个非索引字段而不是两个(都返回相同的文档)。两个查询是否执行相同的集合扫描?

标签: mongodbmongooseindexingmongodb-query

解决方案


要了解 mongo 查询中发生的事情,您可以使用explain. 例如,考虑以下查询: db.getCollection('users').find({"name":"ana"}) 查询非索引字段。您可以在此查询上使用说明,如下所示:

db.getCollection('users').find({"name":"ana"}).explain("executionStats")

部分结果是:

"queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "anonymous-chat.users",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "name" : {
                "$eq" : "ana"
            }
        },
        "winningPlan" : {
            "stage" : "COLLSCAN",
            "filter" : {
                "name" : {
                    "$eq" : "ana"
                }
            },
            "direction" : "forward"
        },
        "rejectedPlans" : []
    },

如您所见,这里我们有COLLSCAN一个集合扫描。现在我们只需查询 _id 并查看结果:

db.getCollection('users').find({"_id":ObjectId("5ee9b6c125b9a9a426d9965f")}).explain("executionStats")

结果如下:

"queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "anonymous-chat.users",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "_id" : {
                "$eq" : ObjectId("5ee9b6c125b9a9a426d9965f")
            }
        },
        "winningPlan" : {
            "stage" : "IDHACK"
        },
        "rejectedPlans" : []
    },

正如我们所看到的,我们IDHACK在查询时只有_id。

现在我们结合 _id 和 name:

db.getCollection('users').find({"_id":ObjectId("5ee9b6c125b9a9a426d9965f"), "name":"ana"}).explain("executionStats")

这是结果:

 "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "anonymous-chat.users",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "$and" : [ 
                {
                    "_id" : {
                        "$eq" : ObjectId("5ee9b6c125b9a9a426d9965f")
                    }
                }, 
                {
                    "name" : {
                        "$eq" : "ana"
                    }
                }
            ]
        },
        "winningPlan" : {
            "stage" : "FETCH",
            "filter" : {
                "name" : {
                    "$eq" : "ana"
                }
            },
            "inputStage" : {
                "stage" : "IXSCAN",
                "keyPattern" : {
                    "_id" : 1
                },
                "indexName" : "_id_",
                "isMultiKey" : false,
                "multiKeyPaths" : {
                    "_id" : []
                },
                "isUnique" : true,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 2,
                "direction" : "forward",
                "indexBounds" : {
                    "_id" : [ 
                        "[ObjectId('5ee9b6c125b9a9a426d9965f'), ObjectId('5ee9b6c125b9a9a426d9965f')]"
                    ]
                }
            }
        },
        "rejectedPlans" : []
    },

正如我们所见,索引有助于提高查询性能,因为我们有两个阶段,一个IXSCAN(索引扫描)和一个FETCH过滤最后阶段文档的阶段。

现在让我们查询多个非索引字段以了解您的第二个问题:

db.getCollection('users').find({"name":"ana", "appId":1}).explain("executionStats")

"queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "anonymous-chat.users",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "$and" : [ 
                {
                    "appId" : {
                        "$eq" : 1.0
                    }
                }, 
                {
                    "name" : {
                        "$eq" : "ana"
                    }
                }
            ]
        },
        "winningPlan" : {
            "stage" : "COLLSCAN",
            "filter" : {
                "$and" : [ 
                    {
                        "appId" : {
                            "$eq" : 1.0
                        }
                    }, 
                    {
                        "name" : {
                            "$eq" : "ana"
                        }
                    }
                ]
            },
            "direction" : "forward"
        },
        "rejectedPlans" : []
    },

正如我们在上面看到的,对于多个字段只有一个集合扫描。


推荐阅读