Допустим, у меня есть две коллекции: задач и клиентов .
клиентов имеют отношение 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 отключается), я хотел бы услышать об этом!
Заранее спасибо!