Я пытался выяснить причину, по которой созданный мной вид MongoDB был таким медленным. Представление предназначено для коллекции transactions
и возвращает записи с openBalance
, превышающим 0
. Я также запускаю несколько дополнительных этапов агрегирования, чтобы сформировать данные так, как я хочу.
Чтобы ускорить выполнение представления, он использует индекс для целевой коллекции путем сопоставления с индексированным полем на первом этапе конвейера агрегации представления, например:
// View Stage 1
{ "transactions.details.openBalance" : { "$exists" : true, "$gt" : 0.0 } }
После долгих исследований я установил, что агрегация из представления возвращает данные очень быстро. Что медленно, так это подсчет, который выполняется как часть конечной точки:
let count = await db.collection('view_transactions_report').find().count();
Итак, сейчас я пытаюсь понять, почему счетчик намного медленнее в представлении, чем в базовой коллекции, и что я могу сделать, чтобы ускорить его. Или, может быть, есть альтернативный способ генерации счетчика?
Базовая коллекция имеет около 800 000 записей, но счет возвращается быстро. Но подсчет представления, который возвращает только отфильтрованный набор из 10 000 из этих 800 000 записей, возвращается гораздо медленнее. Что касается специфики, я говорю о 3/4 секунды для возврата счетчика в коллекции, стихов шесть секунд для возврата счетчика в представлении монго.
Итак, во-первых, почему счетчик намного медленнее в представлении (с гораздо меньшим набором данных), чем в базовом наборе, и, во-вторых, что я могу сделать, чтобы определить скорость счета для представления?
У меня есть пара других запросов агрегации, которые я выполняю, чтобы определить totalCustomers
и totalOpenBalance
, которые также, кажется, работают медленно (см. Код ниже).
Соответствующая часть моего кода функции конечной точки выглядит так:
// previous code
let count = await db.collection('view_transaction_report').find(search).count();
let totalCustomers = await db.collection('view_transaction_report').find(search).count({
$sum: "customer._id"
});
let result = {};
if (totalCustomers > 0) {
result = await db.collection('view_transaction_report').aggregate([{
$match: search,
},
{
$group: {
_id: null,
totalOpenBalance: {
$sum: '$lastTransaction.details.openBalance'
}
}
}
]).next();
}
db.collection('view_transaction_report').find(search).skip(skip).limit(pagesize).forEach(function (doc) {
docs.push(doc);
}, function (err) {
if (err) {
if (!ioOnly) {
return next(err);
} else {
return res(err);
}
}
if (ioOnly) {
res({
sessionId: sessID,
count: count,
data: docs,
totalCustomers: totalCustomers,
totalOpenBalance: result.totalOpenBalance
});
} else {
res.send({
count: count,
data: docs,
totalCustomers: totalCustomers,
totalOpenBalance: result.totalOpenBalance
});
}
});
В терминах executionStats
это то, что показано для секции queryPlanner
сгенерированного представления:
"queryPlanner" : {
"plannerVersion" : 1.0,
"namespace" : "vio.transactions",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"transactions.details.openBalance" : {
"$gt" : 0.0
}
},
{
"transactions.destails.openBalance" : {
"$exists" : true
}
}
]
},
"winningPlan" : {
"stage" : "CACHED_PLAN",
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"transactions.details.openBalance" : {
"$exists" : true
}
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"transactions.details.openBalance" : 1.0
},
"indexName" : "openBalance",
"isMultiKey" : true,
"multiKeyPaths" : {
"transactions.details.openBalance" : [
"transactions",
"transactions.details"
]
},
"isUnique" : false,
"isSparse" : true,
"isPartial" : false,
"indexVersion" : 2.0,
"direction" : "forward",
"indexBounds" : {
"transactions.details.openBalance" : [
"(0.0, inf.0]"
]
}
}
}
},
"rejectedPlans" : [
]
}