Должны ли стадии MongoDB избегать FETCH при совпадении INDEX? - PullRequest
0 голосов
/ 24 октября 2019

Соответственно, MongoDB должен пропустить этап FETCH, когда индекс обращается к запросу.

Если я правильно понял, в этих предложениях объясняется, что:

Покрытые запросы Когда индекс охватываетВ запросе MongoDB может как соответствовать условиям запроса, так и возвращать результаты, используя только ключи индекса;т. е. MongoDB не нужно проверять документы из коллекции для возврата результатов.

Когда индекс покрывает запрос, результат объяснения имеет этап IXSCAN, который не является потомком этапа FETCH, и в executeStats, totalDocsExamined равен 0.

В более ранних версиях MongoDB cursor.explain () возвращал поле indexOnly, чтобы указать, покрывал ли индекс запрос. (https://docs.mongodb.com/manual/reference/explain-results/)

И это

С учетом этого запрос занимает менее 2 мс. Поскольку индекс «покрыл» запрос, MongoDB смогсопоставьте условия запроса и верните результаты, используя только ключи индекса; даже не нужно проверять документы из коллекции, чтобы вернуть результаты. (Если вы видите этап IXSCAN, который не является дочерним по отношению к этапу FETCH, в плане выполнения тогдаиндекс «покрыл» запрос.) (https://studio3t.com/knowledge-base/articles/mongodb-index-strategy/)

Но в тестовом сценарии это не происходит:

Пример для тестирования:

db.Test.insert({"Field1":"data on field1: 1","Field2":"data on field2: 1"});
db.Test.insert({"Field1":"data on field1: 2","Field2":"data on field2: 2"});
db.Test.insert({"Field1":"data on field1: 3","Field2":"data on field2: 3"});
db.Test.insert({"Field1":"data on field1: 4","Field2":"data on field2: 4"});
db.Test.insert({"Field1":"data on field1: 5","Field2":"data on field2: 5"});
db.Test.insert({"Field1":"data on field1: 6","Field2":"data on field2: 6"});

После того как я создал индекс для Field2.

db.Test.createIndex({"Field2":1})

И затем я запрашиваю коллекцию:

db.Test.find({"Field2":"data on field2: 5"}).explain("executionStats");

Я ожидал этап IDXSCAN, который не является дочерним по отношению к этапу FETCH. Но вывод выглядит так:

[...]
"winningPlan" : {
            "stage" : "FETCH",
            "inputStage" : {
                "stage" : "IXSCAN",
                "keyPattern" : {
                    "Campo2" : 1.0
                },
                "indexName" : "Field2_1",
                "isMultiKey" : false,
                "multiKeyPaths" : {
                    "Campo2" : []
                },
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 2,
                "direction" : "forward",
                "indexBounds" : {
                    "Field2" : [ 
                        "[\"data on field2: 5", \"data on field2: 5\"]"
                    ]
                }
            }
        },
[...]

Существует два этапа: один «этап»: «FETCH», и его дочерний элемент «этап»: «IXSCAN»,.

Может кто-нибудь объяснить, в чем заключается недоразумение?

*** О ПРОЕКТЕ

При выполнении запроса с проекцией

"winningPlan" : {
            "stage" : "PROJECTION",
            "transformBy" : {
                "Campo2" : 1.0
            },
            "inputStage" : {
                "stage" : "FETCH",
                "inputStage" : {
                    "stage" : "IXSCAN",
                    "keyPattern" : {
                        "Field2" : 1.0
                    },
                    "indexName" : "Field2_1",
                    "isMultiKey" : false,
                    "multiKeyPaths" : {
                        "Campo2" : []
                    },
                    "isUnique" : false,
                    "isSparse" : false,
                    "isPartial" : false,
                    "indexVersion" : 2,
                    "direction" : "forward",
                    "indexBounds" : {
                        "Field2" : [ 
                            "[\"data on field2: 5", \"data on field2: 5\"]"
                        ]
                    }
                }
            }
        },

С ответом Адама: он работал!

Я понял, что проекция не должна включать "_id", чтобы избежать FETCH.

1 Ответ

2 голосов
/ 24 октября 2019

В вашем запросе не указана проекция , что означает, что он вернет все поля в документе. Это означает, что индекс { Field2: 1 } не охватывает запрос, поскольку он содержит только одно поле.

Следующий запрос должен быть полностью покрыт и не должен иметь стадии FETCH. Обратите внимание, что проекция явно исключает поле _id, так как это будет включено в проекцию, если не указано иное :

    db.Test.find(
      {"Field2":"data on field2: 5"},
      {"Field2" : 1, "_id" : 0 }
    ).explain("executionStats");

Вывод:

{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "foo.Test",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "Field2" : {
                "$eq" : "data on field2: 5"
            }
        },
        "winningPlan" : {
            "stage" : "PROJECTION",
            "transformBy" : {
                "Field2" : 1,
                "_id" : 0
            },
            "inputStage" : {
                "stage" : "IXSCAN",
                "keyPattern" : {
                    "Field2" : 1
                },
                "indexName" : "Field2_1",
                "isMultiKey" : false,
                "multiKeyPaths" : {
                    "Field2" : [ ]
                },
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 2,
                "direction" : "forward",
                "indexBounds" : {
                    "Field2" : [
                        "[\"data on field2: 5\", \"data on field2: 5\"]"
                    ]
                }
            }
        },
        "rejectedPlans" : [ ]
    },
    "executionStats" : {
        "executionSuccess" : true,
        "nReturned" : 1,
        "executionTimeMillis" : 1,
        "totalKeysExamined" : 1,
        "totalDocsExamined" : 0,
        "executionStages" : {
            "stage" : "PROJECTION",
            "nReturned" : 1,
            "executionTimeMillisEstimate" : 0,
            "works" : 2,
            "advanced" : 1,
            "needTime" : 0,
            "needYield" : 0,
            "saveState" : 0,
            "restoreState" : 0,
            "isEOF" : 1,
            "invalidates" : 0,
            "transformBy" : {
                "Field2" : 1,
                "_id" : 0
            },
            "inputStage" : {
                "stage" : "IXSCAN",
                "nReturned" : 1,
                "executionTimeMillisEstimate" : 0,
                "works" : 2,
                "advanced" : 1,
                "needTime" : 0,
                "needYield" : 0,
                "saveState" : 0,
                "restoreState" : 0,
                "isEOF" : 1,
                "invalidates" : 0,
                "keyPattern" : {
                    "Field2" : 1
                },
                "indexName" : "Field2_1",
                "isMultiKey" : false,
                "multiKeyPaths" : {
                    "Field2" : [ ]
                },
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 2,
                "direction" : "forward",
                "indexBounds" : {
                    "Field2" : [
                        "[\"data on field2: 5\", \"data on field2: 5\"]"
                    ]
                },
                "keysExamined" : 1,
                "seeks" : 1,
                "dupsTested" : 0,
                "dupsDropped" : 0,
                "seenInvalidated" : 0
            }
        }
    },
    "serverInfo" : {
    ...
    },
    "ok" : 1,
    ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...