У меня возникли проблемы с производительностью агрегирования MongoDB.
В моей базе данных содержится 43 000 000 документов, и когда я пытаюсь вызвать бэкэнд, он никогда не отвечает (я уверен, что проблема связана с БД, с меньшим набором документов все работает нормально).
Я на самом деле использую Node.js и это модуль Mongoose.
Это образец модели
var PingSchema = new Schema({
provider: String,
from_zone: String,
to_zone: String,
from_host: String,
to_host: String,
icmp_seq: Number,
ttl: Number,
time: Number,
timestamp: { type : Date, default: Date.now }
}).plugin(mongoosePaginate);
const Ping = mongoose.model('Ping', PingSchema);
Я использую Express для создания некоторых маршрутов, и это код двух основных запросов из бэкэнда
router.route('/pings/query/avgOfEveryPingOfSelectedDate').get(async (req, res, next) => {
var start, end, sameRegion;
start = new Date(req.query.start + "T00:00:00-00:00");
end = new Date(req.query.end + "T23:59:59-00:00");
sameRegion = parseInt(req.query.sameRegion);
Ping.aggregate()
.project({sameRegion: {$cmp: ['$from_zone', '$to_zone']}, provider: "$provider", time: "$time", timestamp: "$timestamp"})
.match({$and: [{sameRegion: sameRegion}, {timestamp: {$gte: start, $lte: end}}]})
.group({_id : "$provider", avg: { $avg: "$time" }, count: { $sum: 1 }})
.exec(function (err, resp) {
if (err) {
// TODO
console.log(err);
} else {
res.json(resp);
}
})
});
router.route('/pings/query/avgOfEveryDayOfSelectedYear').get(async (req, res, next) => {
var year, provider, sameRegion;
year = parseInt(req.query.year);
provider = req.query.provider;
sameRegion = parseInt(req.query.sameRegion);
Ping.aggregate()
.project({sameRegion: {$cmp: ['$from_zone', '$to_zone']}, provider: "$provider", time: "$time", timestamp: "$timestamp", "year": {"$year":"$timestamp"}, "dayOfYear": { "$dayOfYear": "$timestamp" }})
.match({$and: [{sameRegion: sameRegion}, {year: year}, {provider: provider}]})
.group({_id : {"provider": "$provider", "dayOfYear": "$dayOfYear"}, avg: { $avg: "$time" }, count: { $sum: 1 }})
.sort({"_id": 1})
.exec(function (err, resp) {
if (err) {
// TODO
console.log(err);
} else {
res.json(resp);
}
})
});
Первый запрос вводит две даты и возвращает среднее время всех пингов в этом диапазоне. Второй занимает год и выбранного провайдера (простая строка) и возвращает среднее значение всех пингов, соответствующих условиям.
Я спрашиваю, является ли мой код неправильным (или он нуждается в некоторой оптимизации), или мне нужно что-то делать для кэширования или распараллеливания (может быть, MongoDB имеет некоторые особенности в этом отношении?).
Спасибо всем заранее.
РЕДАКТИРОВАТЬ 1:
Может быть, allowDiskOption или некоторые индексы полезны?
РЕДАКТИРОВАТЬ 2:
Я реализовал allowDiskOption и некоторые индексы для провайдера и метки времени, но запрос все еще медленный.
Проблема в здесь : эти запросы выполняются слишком медленно для этого большого набора данных.
// By day in month
db.pings.aggregate(
[
{$project: {month: {"$month":"$timestamp"}}},
{$match: {$and: [{provider: "AWS"},{month:8}]}},
{$group:{_id: {"$dayOfYear":"$timestamp"}, avg: {$avg:"$time"}}},
{$sort:{_id:1}}
],
{
allowDiskUse: true
}
)
// In two dates
db.pings.aggregate(
[
{$match:{timestamp:{$gte:ISODate("2018-08-10T00:00:00.0Z"), $lte:ISODate("2018-08-18T23:59:59.0Z")}}},
{$group:{_id: "$provider", avg: {$avg:"$time"}}}
],
{
allowDiskUse: true
}
)
Теперь я спрашиваю: Как я могу оптимизировать эти запросы?
Еще раз спасибо