Итак, во время некоторого обзора кода я решил улучшить производительность существующих запросов, улучшив одну агрегацию, которая была такой:
.aggregate([
//difference starts here
{
"$lookup": {
"from": "sessions",
"localField": "_id",
"foreignField": "_client",
"as": "sessions"
}
},
{
$unwind: "$sessions"
},
{
$match: {
"sessions.deleted_at": null
}
},
//difference ends here
{
$project: {
name: client_name_concater,
email: '$email',
phone: '$phone',
address: addressConcater,
updated_at: '$updated_at',
}
}
]);
до этого:
.aggregate([
//difference starts here
{
$lookup: {
from: 'sessions',
let: {
id: "$_id"
},
pipeline: [
{
$match: {
$expr: {
$and:
[
{
$eq: ["$_client", "$$id"]
}, {
$eq: ["$deleted_at", null]
},
]
}
}
}
],
as: 'sessions'
}
},
{
$match: {
"sessions": {$ne: []}
}
},
//difference ends here
{
$project: {
name: client_name_concater,
email: '$email',
phone: '$phone',
address: addressConcater,
updated_at: '$updated_at',
}
}
]);
Я подумал, что второй вариант должен быть лучше, так как у нас на один этап меньше, но разница в производительности огромна, наоборот, первый запрос выполняется в среднем ~ 40 мсек, другой - от 3,5 до 5 секунд, в 100 раз больше. Другая коллекция (сеансы) содержит около 120 документов, в то время как эта около 152, но все же, даже если это было приемлемо из-за размера данных, почему разница между этими двумя, в основном, не одно и то же, мы просто добавляем условие соединения в конвейере с другим основным условием соединения. Я что-то упустил?
Некоторые функции или переменные, включенные в него, в основном состоят из c или конкатенации, которые не должны влиять на часть поиска.
Спасибо
EDIT:
Добавлены планы запросов для версии 1:
{
"stages": [
{
"$cursor": {
"query": {
"$and": [
{
"deleted_at": null
},
{}
]
},
"fields": {
"email": 1,
"phone": 1,
"updated_at": 1,
"_id": 1
},
"queryPlanner": {
"plannerVersion": 1,
"namespace": "test.clients",
"indexFilterSet": false,
"parsedQuery": {
"deleted_at": {
"$eq": null
}
},
"winningPlan": {
"stage": "COLLSCAN",
"filter": {
"deleted_at": {
"$eq": null
}
},
"direction": "forward"
},
"rejectedPlans": []
}
}
},
{
"$lookup": {
"from": "sessions",
"as": "sessions",
"localField": "_id",
"foreignField": "_client",
"unwinding": {
"preserveNullAndEmptyArrays": false
}
}
},
{
"$project": {
"_id": true,
"email": "$email",
"phone": "$phone",
"updated_at": "$updated_at"
}
}
],
"ok": 1
}
Для версии 2:
{
"stages": [
{
"$cursor": {
"query": {
"deleted_at": null
},
"fields": {
"email": 1,
"phone": 1,
"sessions": 1,
"updated_at": 1,
"_id": 1
},
"queryPlanner": {
"plannerVersion": 1,
"namespace": "test.clients",
"indexFilterSet": false,
"parsedQuery": {
"deleted_at": {
"$eq": null
}
},
"winningPlan": {
"stage": "COLLSCAN",
"filter": {
"deleted_at": {
"$eq": null
}
},
"direction": "forward"
},
"rejectedPlans": []
}
}
},
{
"$lookup": {
"from": "sessions",
"as": "sessions",
"let": {
"id": "$_id"
},
"pipeline": [
{
"$match": {
"$expr": {
"$and": [
{
"$eq": [
"$_client",
"$$id"
]
},
{
"$eq": [
"$deleted_at",
null
]
}
]
}
}
}
]
}
},
{
"$match": {
"sessions": {
"$not": {
"$eq": []
}
}
}
},
{
"$project": {
"_id": true,
"email": "$email",
"phone": "$phone",
"updated_at": "$updated_at"
}
}
],
"ok": 1
}
Одно примечание: коллекция объединенных сеансов имеет определенные свойства с очень большие данные (некоторые импортированные данные), поэтому я думаю, что это может каким-то образом повлиять на размер запроса из-за этих данных? Но почему разница между двумя версиями $ lookup?