Почему Mongodb будет использовать мой индекс только если я использую подсказку - PullRequest
0 голосов
/ 08 ноября 2019

У меня есть база данных с полем типа 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 () в мои запросы, и я озадачен, почему он отказывается использовать индекс.

Мой индекс редкий и не уникальный.

Я пробовал другиеиндексы и поиск, но я не могу найти ссылки на эту проблему в переполнении стека или в другом месте.

1 Ответ

1 голос
/ 08 ноября 2019

В соответствии с документацией MongoDB

Если разреженный индекс приведет к неполному набору результатов для запросов и операций сортировки, MongoDB не будет использовать этот индекс, если в подсказке () явно не указан индекс.

Чтобы использовать разреженный индекс, явно укажите индекс с помощью hint ()

Поскольку hint () заставляет оптимизатор запросов использовать индекс при выполнении запроса

...