当您有索引时,使用`min`和`max`的速度要快于$ gte和$ lt的速度?为什么?

时间:2019-03-22 18:45:41

标签: mongodb

很抱歉,我是MongoDB的新手。

假设您有一个名为“学生”的集合,并在一个名为“成绩”的字段上建立了索引。其中哪个会更快?

db.students.find({"grade": {$gte: 50}, "grade": {$lt: 90}})

db.students.find().min("grade": 50).max("grade": 90)

除了能够为第二个选项提供hint之外,第二个选项是否存在并且具有优势?

1 个答案:

答案 0 :(得分:0)

第一个查询将更快,因为它允许在索引上进行边界。使用explain时最好看到这一点。

例如:

db.stack.find({ "grade" : { "$lt" : 90, "$gt" : 50 } }).explain()

{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "test.stack",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "$and" : [
                {
                    "grade" : {
                        "$lt" : 90
                    }
                },
                {
                    "grade" : {
                        "$gt" : 50
                    }
                }
            ]
        },
        "winningPlan" : {
            "stage" : "FETCH",
            "inputStage" : {
                "stage" : "IXSCAN",
                "keyPattern" : {
                    "grade" : 1
                },
                "indexName" : "grade_1",
                "isMultiKey" : false,
                "multiKeyPaths" : {
                    "grade" : [ ]
                },
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 2,
                "direction" : "forward",
                "indexBounds" : {
                    "grade" : [
                        "(50.0, 90.0)"
                    ]
                }
            }
        },
        "rejectedPlans" : [ ]
    },

上方的indexBounds字段显示查询仅扫描索引的子集,尤其是50到90之间的键。

相比之下,另一种查询形式是扫描索引范围,然后解析结果的游标以执行minmax函数:

db.stack.find().min({ "grade" : 50 }).max({"grade" : 90 }).explain()
{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "test.stack",
        "indexFilterSet" : false,
        "parsedQuery" : {

        },
        "winningPlan" : {
            "stage" : "FETCH",
            "inputStage" : {
                "stage" : "IXSCAN",
                "keyPattern" : {
                    "grade" : 1
                },
                "indexName" : "grade_1",
                "isMultiKey" : false,
                "multiKeyPaths" : {
                    "grade" : [ ]
                },
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 2,
                "direction" : "forward",
                "indexBounds" : {

                }
            }
        },
        "rejectedPlans" : [ ]
    },

请注意上面的indexBounds是空的。

有道理吗?

另一个重要说明:问题中列出的查询将无法按预期方式运行,因为它将仅以当前形式应用$lte : 90过滤器。

在单个字段上应用多个过滤器的查询将需要使用$and operator对多个条件执行逻辑AND。在上面的示例中,我将多个过滤器组合为一个条件:

{ "grade" : { "$lt" : 90, "$gt" : 50 } }

这应该与:

{ 
  "$and" : [ 
    { grade : { "$gt" : 50 } }, 
    { grade: { "$lt" : 90 } } 
  ] 
}