#mongodb #mgo
#mongodb #mgo
Вопрос:
Я работаю над проектом Golang (db MongoDB). Я выполнил приведенный ниже запрос, но загрузка данных занимает слишком много времени. При этом я получаю данные из 2 коллекций с несколькими этапами.
db.getCollection('Collection1').aggregate([
{
"$lookup": {
"localField": "uid",
"from": "collection2",
"foreignField": "_id",
"as": "user_info"
}
},
{
"$unwind": "$user_info"
},
{
"$lookup": {
"localField": "cid",
"from": "collection3",
"foreignField": "_id",
"as": "cust_info"
}
},
{
"$lookup": {
"from": "logs",
"let": {"id": "$_id"},
"pipeline": [
{"$match": {"$expr": {"$eq": ["$$id", "$log_id"]}}},
{"$sort": {"log_type": 1}}],
"as": "logs_data"
}
},
{
"$sort": {"logs_data.logged_on":-1}
},
{
"$skip": 1
},
{
"$limit": 2
},
])
Мое требование — добавить сортировку по времени 2 в одном запросе:
- В массиве журналов
"$sort": {"log_type": 1}}
- Для конечного результата
"$sort": {"logs_data.logged_on":-1}
Для этого я попробовал следующие индексы:
{"logged_on" : -1}
{"log_id":1, "log_type":1}
Но выполнение запроса занимает еще 6-7 секунд.
Если я удаляю "$sort": {"logs_data.logged_on":-1}
, то он работает быстро, но при такой сортировке это занимает слишком много времени.
как и что я могу сделать, чтобы увеличить время отклика.
Комментарии:
1. Будет ли
logs
коллекция содержать какие-либо документы, которые не соответствуют_id
fromcollection1
?2. @Joe Нет, это невозможно. Журналы не содержат документов, которые не соответствуют «_id» из коллекции1
Ответ №1:
Что делает эта агрегация:
- извлеките все документы из коллекции1
- для каждого документа в коллекции1 найдите один документ в коллекции2
- для каждого документа в коллекции1 найдите один документ в коллекции3
- для каждого документа в коллекции1 найдите все реализованные документы в журналах
- для каждого документа в коллекции1 выполните сортировку документов, извлеченных из журналов, в памяти
- выполните сортировку в памяти, чтобы упорядочить документы
- сохраните 2 из этих документов и выбросьте остальные
Для каждого документа в коллекции1 это 3 выборки документов (плюс неизвестное количество выборок в # 4), 2 сканирования индекса и сортировка в памяти.
Если в коллекции 1 имеется нетривиальное количество документов, это огромная работа, которая тратится впустую для всех документов, кроме 2.
Если можно с уверенностью предположить, что каждый документ в logs
содержит log_id
, который сопоставляется с collection1
, вы могли бы:
- создайте индекс на
{logged_on:1, log_id:1}
- запустите агрегацию для коллекции журналов
- Сортировать по
logged_on: 1
- проект
{logged_on:1, log_id:1, _id:0}
(это делает первую часть агрегации полностью покрытой указанным выше индексом) - группируйте по
log_id
, принимая$first
значениеlogged_on
- сортировать по
logged_on: 1
(группировка распределяет сортировку) - пропустить и ограничить по желанию
- поиск из
collection1
с помощью локальногоlog_id
внешнего_id
- Замените Root на newRoot, являющийся просмотренным документом
- выполните существующие этапы конвейера, которые вы использовали — на этот раз они будут извлекать / сортировать только для 2 документов, которые вы хотите вернуть.