Невероятно низкая производительность запросов с $ lookup и конвейером агрегации «sub» - PullRequest
0 голосов
/ 31 января 2019

Допустим, у меня есть две коллекции: задач и клиентов .

клиентов имеют отношение 1: n с задачами через поле customerId у клиентов.

Теперь у меня есть представление, где мне нужно отображать задачи с именами клиентов.И мне также нужно иметь возможность фильтровать и сортировать по именам клиентов.Это означает, что я не могу выполнить этап $ limit или $ match до поиска $ в следующем запросе.

Итак, вот мой пример запроса:

db.task.aggregate([
    {
        "$match": {
            "_deleted": false
        }
    },
    "$lookup": {
        "from": "customer",
        "let": {
            "foreignId": "$customerId"
        },
        "pipeline": [
            {
                "$match": {
                    "$expr": {
                        "$and": [
                            {
                                "$eq": [
                                    "$_id",
                                    "$$foreignId"
                                ]
                            },
                            {
                              "$eq": [
                                "$_deleted",
                                false
                              ]
                            }
                        ]
                    }
                }
            }
        ],
        "as": "customer"
    },
    {
        "$unwind": {
            "path": "$customer",
            "preserveNullAndEmptyArrays": true
            }
    },
    {
        "$match": {
            "customer.name": 'some_search_string'
        }
    },
    {
        "$sort": {
            "customer.name": -1
        }
    },
    {
        "$limit": 35
    },
    {
        "$project": {
            "_id": 1,
            "customer._id": 1,
            "customer.name": 1,
            "description": 1,
            "end": 1,
            "start": 1,
            "title": 1
        }
    }
])

Этот запрос становится невероятно медленнымкогда коллекции растут в размере.С 1000 задачами и 20 заказчиками для получения результата уже требуется около 500 мс.

Я знаю, что это происходит потому, что оператор $ lookup должен выполнить сканирование таблицы для каждой строки, которая входит в стадию поиска конвейера агрегации.

Я пытался установить индексы, как описано здесь: Плохая производительность агрегирования поиска , но это, похоже, не оказывает никакого влияния.

Моим следующим предположением было то, что "sub "-pipeline на этапе $ lookup не может использовать индексы, поэтому я заменил его на простой

"$lookup": {
    "from": "customer",
    "localField": "customerId",
    "foreignField": "_id",
    "as": "customer"
}

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

Я пробовал следующие индексы :

  • По возрастанию, по убыванию, хеширование и текстовый индекс по customerId
  • По возрастанию, по убыванию, хеширование и текстовый индекс по customer.name

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

Дополнительная информация: я использую трех членовнабор реплик.Я нахожусь на MongoDB 4.0.

Обратите внимание: я знаю, что я использую нереляционную базу данных для достижения высокореляционных целей, но в этом проекте MongoDB был нашим выбором из-за его функции ChangeStream.Если кто-нибудь знает другую базу данных с сопоставимой функцией (push-уведомления в реальном времени об изменениях), которую можно запускать на месте (так что Firebase отключается), я хотел бы услышать об этом!

Заранее спасибо!

Ответы [ 2 ]

0 голосов
/ 23 февраля 2019

Я выяснил, почему не использовались мои индексы.

Я запросил коллекцию с использованием другого сопоставления, чем собственное сопоставление коллекции.Но индексы id в коллекции всегда реализуются с использованием параметров сортировки по умолчанию для коллекций.

Поэтому индексы не использовались.

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

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

0 голосов
/ 13 февраля 2019

Рассматривали ли вы наличие одной коллекции для клиента с задачами в виде встроенного массива в каждом документе?Таким образом, вы сможете индексировать поиск как в полях клиента, так и в поле задач.

...