Повышение производительности запроса MongoDB $ geoIntersects - PullRequest
0 голосов
/ 25 апреля 2018

Я пытаюсь улучшить запрос MongoDB, который запрашивает документы по точке.Документы имеют простую геометрию многоугольника с шириной от 10 до 100 точек и шириной от 50 до 5000 метров.Пример документа:

{
    "_id" : UUID("9175a387-4b0c-48ab-a74a-a8b200cc5285"),
    "seconds" : NumberLong(123),
    "geometry" : {
        "type" : "Polygon",
        "coordinates" : [ [ 
            [ 28.08093, -26.00869 ], 
            [ 28.09113, -26.01888 ], 
            [ 28.09486, -26.03282 ],  
            [ 28.08093, -26.00869 ] ]
        ]
    }
}

Запрос использует $geoIntersects фильтрацию по точке и упорядочивает результаты по seconds.Существует геопространственный индекс по геометрии и секундам, и я проверил, что он действительно используется во время этого запроса:

IXSCAN { geometry: "2dsphere", seconds: 1 }

Поскольку мы используем драйвер MongoDB C #, это не точный запрос, а то, что яизвлекается с помощью профилирования, но пример запроса выглядит следующим образом:

db.getCollection('fooCollection')
.find({
    "geometry" : {
        "$geoIntersects" : {
            "$geometry" : {
                "type" : "Point",
                "coordinates" : [ 28.04, -26.19 ]
            } } } })
.sort({ "seconds" : 1 })
.projection({ "geometry" : 0 })

Поскольку для запросов нам нужна только геометрия, мы также проецируем только поле id и поле секунд, чтобы уменьшить ввод-вывод данных.Геометрия является приблизительной и не должна быть идеальной парой.

Этот запрос используется во время чрезвычайно критически важной задачи и является узким местом, выполнение которого занимает около 170 мс.Это далеко не так быстро, как другие наши монго запросы, которые обычно завершаются за 20-30 мс до конца.

Я недостаточно знаю о внутренностях запроса $geoIntersects или геопространственных индексах, чтобы узнать, есть ли способ улучшить производительность этого запроса.Некоторые (довольно трудоемкие) идеи, в которых я не уверен, заслуживают реализации:

  • Упростите всю геометрию, чтобы использовать меньше точек.

  • Используйте более простую справочную геометрию, чем 2dsphere.Плоское приближение было бы достаточно близко для наших целей.

  • Ядерная опция: кэшировать всю геометрию в памяти и выполнить обнаружение столкновений самостоятельно.Это зависит от написания такого алгоритма и поиска индекса, который был бы эффективнее, чем MongoDB.

Чего-то мне не хватает в этой операции? Каков наилучший способ повысить производительность запроса MongoDB $geoIntersects?

РЕДАКТИРОВАТЬ: добавлены следующие выходные данные объяснения () по запросу:

{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "fooCollection",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "geometry" : {
                "$geoIntersects" : {
                    "$geometry" : {
                        "type" : "Point",
                        "coordinates" : [ 
                            28.04, 
                            -26.19
                        ]
                    }
                }
            }
        },
        "winningPlan" : {
            "stage" : "FETCH",
            "filter" : {
                "geometry" : {
                    "$geoIntersects" : {
                        "$geometry" : {
                            "type" : "Point",
                            "coordinates" : [ 
                                28.04, 
                                -26.19
                            ]
                        }
                    }
                }
            },
            "inputStage" : {
                "stage" : "IXSCAN",
                "keyPattern" : {
                    "geometry" : "2dsphere",
                    "seconds" : 1
                },
                "indexName" : "Geometry_Seconds",
                "isMultiKey" : true,
                "multiKeyPaths" : {
                    "geometry" : [ 
                        "geometry"
                    ],
                    "seconds" : []
                },
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 2,
                "direction" : "forward",
                "indexBounds" : {
                    "geometry" : [ 
                        "[2202260217784172544, 2202260217784172544]", 
                        "[2203386117691015168, 2203386117691015168]", 
                        "[2203667592667725824, 2203667592667725824]", 
                        "[2233785415175766016, 2233785415175766016]"
                    ],
                    "seconds" : [ 
                        "[MinKey, MaxKey]"
                    ]
                }
            }
        },
        "rejectedPlans" : []
    },
    "executionStats" : {
        "executionSuccess" : true,
        "nReturned" : 29,
        "executionTimeMillis" : 5,
        "totalKeysExamined" : 58,
        "totalDocsExamined" : 46,
        "executionStages" : {
            "stage" : "FETCH",
            "filter" : {
                "geometry" : {
                    "$geoIntersects" : {
                        "$geometry" : {
                            "type" : "Point",
                            "coordinates" : [ 
                                28.04, 
                                -26.19
                            ]
                        }
                    }
                }
            },
            "nReturned" : 29,
            "executionTimeMillisEstimate" : 0,
            "works" : 58,
            "advanced" : 29,
            "needTime" : 28,
            "needYield" : 0,
            "saveState" : 0,
            "restoreState" : 0,
            "isEOF" : 1,
            "invalidates" : 0,
            "docsExamined" : 46,
            "alreadyHasObj" : 0,
            "inputStage" : {
                "stage" : "IXSCAN",
                "nReturned" : 46,
                "executionTimeMillisEstimate" : 0,
                "works" : 58,
                "advanced" : 46,
                "needTime" : 11,
                "needYield" : 0,
                "saveState" : 0,
                "restoreState" : 0,
                "isEOF" : 1,
                "invalidates" : 0,
                "keyPattern" : {
                    "geometry" : "2dsphere",
                    "seconds" : 1
                },
                "indexName" : "Geometry_Seconds",
                "isMultiKey" : true,
                "multiKeyPaths" : {
                    "geometry" : [ 
                        "geometry"
                    ],
                    "seconds" : []
                },
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 2,
                "direction" : "forward",
                "indexBounds" : {
                    "geometry" : [ 
                        "[2202260217784172544, 2202260217784172544]", 
                        "[2203386117691015168, 2203386117691015168]", 
                        "[2203667592667725824, 2203667592667725824]", 
                        "[2233785415175766016, 2233785415175766016]"
                    ],
                    "seconds" : [ 
                        "[MinKey, MaxKey]"
                    ]
                },
                "keysExamined" : 58,
                "seeks" : 12,
                "dupsTested" : 46,
                "dupsDropped" : 0,
                "seenInvalidated" : 0
            }
        }
    },
    "serverInfo" : {
        "host" : "LAPTOP-F7A8SNP5",
        "port" : 27017,
        "version" : "3.6.3",
        "gitVersion" : "9586e557d54ef70f9ca4b43c26892cd55257e1a5"
    },
    "ok" : 1.0
}
...