我正在开发一个MEAN webapp。我已经有两天时间考虑以下哪两种方法有更好的表现。
我目前有一个MongoDB数据库:
在仪表板中,我需要获得所有客户的有效租赁(每个客户50-100租赁m.ax)。然后,对于每次租赁,我需要通过deviceId字段为每个设备获取其设备,也是deviceId的最后读取文档。
//1. I get the client rentals
Rental.find({
start_date: {
"$lte": new Date()
},
end_date: {
"$gte": new Date()
},
clientId : ObjectId(req.params.clientId)
}, 'deviceId', function(err, Rentals) {
if (err) {
res.send(err)
} else {
//2. I create an array with the required deviceIds
var finalDevices = Rentals.map(function (obj) {
return obj.deviceId;
});
//3. In paralel
Async.parallel([
function(callback) {
//3.1 Get devices by the array of deviceIs (only one BD query)
Device.find({
"_id": { "$in": finalDevices }
},
function(err, devices) {
if (err) {
callback(err, null);
} else {
callback(null, devices)
}
});
},
function(callback) {
//3.1 Get last reading for each device (only one BD query)
Reading.aggregate([
{ $match: { "deviceId": { "$in": deviceIds} } },
{
$group: {
deviceId: "$deviceId",
maxCreatedAt: { $max: "$createdAt" }
}
}
],function(err, readings) {
if (err) {
callback(err, null);
} else {
callback(null, readings)
}
})
}
],
// optional callback
function(err, results) {
// create and object matching Rentals array, devices array and readings array by deviceId. Pending. I suppose I'll need to iterate through each array which will be bad performing...
// [{
// rental: ...,
// device: ...,
// last_reading: ...
//}]
});
}
});
var finalData = [];
//1. I get the client rentals
Rental.find({
start_date: {
"$lte": new Date()
},
end_date: {
"$gte": new Date()
},
clientId : ObjectId(req.params.clientId)
}, 'deviceId', function(err, Rentals) {
if (err) {
res.send(err)
} else {
Async.each(Rentals, function(rental, callback) {
//2. for reach rental we get In paralel (1 BD query per rental)
Async.parallel([
function(callback) {
//3.1 Get device by the array of deviceIs (1 BD query per each rental)
Device.findOne({
"_id": rental.deviceId
},
function(err, device) {
if (err) {
callback(err, null);
} else {
callback(null, device)
}
});
},
function(callback) {
//3.1 Get last reading for each device (one BD query per each rental)
Reading.aggregate([
{ $match: { "deviceId": rental.deviceId } },
{
$group: {
deviceId: "$deviceId",
maxCreatedAt: { $max: "$createdAt" }
}
}
],function(err, reading) {
if (err) {
callback(err,null);
} else {
callback(null,reading);
}
})
}
],
// optional callback
function(err, results) {
finalData.push({
rental: rental,
device: results[0],
reading: results[1]
});
});
}, function(err) {
res.send(finalData);
});
}
});
在Option1中,我只进行3次数据库查询,但我需要开发一个最终代码,以便将每次租赁与其设备及其最后读数相匹配。
在option2中,我做了更多的数据库查询,但我不需要额外的代码来匹配每个租用。
哪个选项更好?有更好的方法吗?
答案 0 :(得分:2)
哪一个更快的唯一答案是基准和衡量。我们不能为你做那件事。只有你能做到。
如果要进行理论化(这对于规划合理的测试只有用,你仍然需要进行测试才能知道),那么数据库查询的组件可以按照这样排列(从最慢到最快):
因此,您希望最小化最慢的操作,这意味着最小化数据库必须到达磁盘的时间。现在,这不是一个完全可预测的事情,因为数据库会进行缓存等等,但是将代码编写成更少的数据库操作通常会使数据库有更好的机会来优化工作(假设您没有切换到使用非常低效的数据库操作)。
并且,最小化数据库操作的数量通常也会最小化网络往返次数。
因此,如果您有一种有效的方法来最小化数据库查询的数量,只要您没有进行非常低效的查询或传输的数据超过所需数据,这通常是您的首选。
并且,您通常不需要担心一些额外的CPU来处理高效数据库查询的结果,因为CPU通常是链中最快的链接。
因此,理论上说你的选项1(更少的查询)更可能更快,特别是当数据集变大时。但是,你必须衡量。
但是......数据库在某些方面可能很快而在其他方面很慢,这取决于它们可以缓存的内容,它们索引的内容以及它们通常优化的内容。所以,你必须进行基准测试以找出真正最快的东西。