【问题标题】:Why will Mongodb only use my index if I use hint如果我使用提示,为什么 Mongodb 只会使用我的索引
【发布时间】:2020-03-05 03:51:15
【问题描述】:

我有一个带有索引的 ISODate() 类型字段的数据库(我也尝试过使用字符串字段进行此实验 - 结果相同)。我正在使用 MongoDB (4.x) 的开源版本,当我进行查询/排序以查找最大 _finish_time 时,除非我指定提示,否则不使用索引。

我的查询是:

db.getCollection("test").find({}, { _finish_time: 1}).sort({_finish_time: -1}).limit(1)

解释为:

{ 
    "queryPlanner" : {
        "plannerVersion" : 1.0, 
        "namespace" : "vdm-service-ts-staging.test", 
        "indexFilterSet" : false, 
        "parsedQuery" : {

        }, 
        "winningPlan" : {
            "stage" : "PROJECTION", 
            "transformBy" : {
                "_finish_time" : 1.0
            }, 
            "inputStage" : {
                "stage" : "SORT", 
                "sortPattern" : {
                    "_finish_time" : -1.0
                }, 
                "limitAmount" : 1.0, 
                "inputStage" : {
                    "stage" : "SORT_KEY_GENERATOR", 
                    "inputStage" : {
                        "stage" : "COLLSCAN", 
                        "direction" : "forward"
                    }
                }
            }
        }, 
        "rejectedPlans" : [

        ]
    }, 
    "serverInfo" : {
        "host" : "ip-10-82-245-45.us-west-2.compute.internal", 
        "port" : 27017.0, 
        "version" : "4.0.1", 
        "gitVersion" : "54f1582fc6eb01de4d4c42f26fc133e623f065fb"
    }, 
    "ok" : 1.0, 
    "operationTime" : Timestamp(1573220526, 1), 
    "$clusterTime" : {
        "clusterTime" : Timestamp(1573220526, 1), 
        "signature" : {
            "hash" : BinData(0, "blIkiGcam87SDdbKeZKex/9JXBU="), 
            "keyId" : NumberLong(6715502669504446467)
        }
    }
}

扫描整个集合。当我为可用索引指定提示时,如下所示:

db.getCollection("test").find({}, { _finish_time: 1}).sort({_finish_time: -1}).limit(1).hint("_finish_time")

我得到了查询计划:

{ 
    "queryPlanner" : {
        "plannerVersion" : 1.0, 
        "namespace" : "vdm-service-ts-staging.test", 
        "indexFilterSet" : false, 
        "parsedQuery" : {

        }, 
        "winningPlan" : {
            "stage" : "LIMIT", 
            "limitAmount" : 1.0, 
            "inputStage" : {
                "stage" : "PROJECTION", 
                "transformBy" : {
                    "_finish_time" : 1.0
                }, 
                "inputStage" : {
                    "stage" : "FETCH", 
                    "inputStage" : {
                        "stage" : "IXSCAN", 
                        "keyPattern" : {
                            "_finish_time" : -1.0
                        }, 
                        "indexName" : "_finish_time", 
                        "isMultiKey" : false, 
                        "multiKeyPaths" : {
                            "_finish_time" : [

                            ]
                        }, 
                        "isUnique" : false, 
                        "isSparse" : true, 
                        "isPartial" : false, 
                        "indexVersion" : 2.0, 
                        "direction" : "forward", 
                        "indexBounds" : {
                            "_finish_time" : [
                                "[MaxKey, MinKey]"
                            ]
                        }
                    }
                }
            }
        }, 
        "rejectedPlans" : [

        ]
    }, 
    "serverInfo" : {
        "host" : "ip-10-82-245-45.us-west-2.compute.internal", 
        "port" : 27017.0, 
        "version" : "4.0.1", 
        "gitVersion" : "54f1582fc6eb01de4d4c42f26fc133e623f065fb"
    }, 
    "ok" : 1.0, 
    "operationTime" : Timestamp(1573220603, 3), 
    "$clusterTime" : {
        "clusterTime" : Timestamp(1573220603, 3), 
        "signature" : {
            "hash" : BinData(0, "qsGhD1DpI306XbqtNZDYVINPid8="), 
            "keyId" : NumberLong(6715502669504446467)
        }
    }
}

其中使用索引。我不想在我的查询中添加hint(),我很困惑为什么它拒绝使用索引。

我的索引是稀疏的,不是唯一的。

我尝试了其他索引并四处搜索,但在堆栈溢出或其他地方找不到任何关于此问题的参考。

【问题讨论】:

    标签: mongodb performance indexing hint


    【解决方案1】:

    根据 MongoDB 的文档

    如果稀疏索引会导致查询的结果集不完整 和排序操作,MongoDB 将不会使用该索引,除非提示() 明确指定索引。

    要使用稀疏索引,用hint()显式指定索引

    Ashint() 强制查询优化器在执行查询时使用索引

    【讨论】:

    • 嗯,这完全解释了我的问题 - 但这是违反直觉的。如果我将 { _finish_time: {$exists: true} 添加到我的查询中,那么它确实使用了索引。由于排序和限制,他们似乎仍然可以使用该查询的索引,所有缺少该字段的记录在排序顺序中都是相同的。感谢您的帮助!
    • @user3501690 _finish_time 上的稀疏索引不会包含没有 _finish_time 字段的文档。阻止稀疏索引选择的正确性问题是,某些与“所有文档”的查询过滤器匹配的文档不会使用稀疏索引包含在内。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-20
    • 1970-01-01
    • 1970-01-01
    • 2014-06-17
    • 2015-10-18
    相关资源
    最近更新 更多