新手真诚求教。
我现在正在用Mongoose/MongoDB,为一个小网站存储用户的信息。
在做数据迁移的时候,发现保存的速度奇慢无比。存储前200个数据,只需要几秒,到后来随着数据的增多存储速度直线下降。当到600个的时候已经下降到了1个/秒,1500个的时候已经变成了2个/秒。。。这个速度实在无法接受啊。
经过测试后,我发现问题出现在了插入时与另一个Model交互的地方。是这样的,我有一个User的Model存储信息,同时还有一个Group的Model用来控制用户权限。User有一个groups的数组存储它所属于哪个,Group有一个member的subdocument的数组,存储属于他的user的ObjectId和username方便查询,简而言之就是这俩是个多对多的关系。Group有几十个,用户大概一万左右。
下面是那部分的代码,通过输出的log信息可以发现,速度就是慢在了这部分。数据量越大,这部分的运行时间越长,保存一个User的文档一直都是ms级别的。我尝试着把更改member的操作由addToSet改为了push,但是性能没有显著的提升。
User.prototype.addGroupsAndSave = function (groups, callback) {
log.debug('before adding groups');
// ToDo May have duplicate problems
if (!Array.isArray(groups)) {
groups = [groups];
}
var user = this;
var userRef = {objId: user.id, username: user.username};
async.map(groups, function addToGroup(group, cb) {
Group.findOne({groupName: group}, function (err, group) {
if (err) {
return cb(err);
}
if (_.isEmpty(group)) {
return cb(new Error('No such groups'));
}
// group.member.addToSet(userRef);
group.member.push(userRef);
group.save(cb);
});
},
function (err) {
if (err) {
return callback(err);
}
log.debug('after adding groups');
user.groups.addToSet.apply(user.groups,groups);
user.save(callback);
});
};
如果直接用mongo_native迁移的话应该会快一些,但是因为以前的数据,有一些有问题,我想用Mongoose做验证,而且这样也能测试使用环境下的性能。
问题出在哪了呢?不解决这个问题,不敢部署网站啊,性能太渣了。
几番Google之后,发现问题出在了Mongoose上,对于所有的查询到的结果,其都会进行一番处理,转成MongooseDocuments。结果就是对速度会有很大的影响,相较于MongoDB_native大约是3倍的时间消耗。这个转化是为了方便再一次save时进行验证的,所以如果对大文档是只读的查询,最好在查询时设置 lean。
但是我的情况不一样,我需要更新我的member数组,不过我并不特别关心更新了后的member数组会变成什么样,而且对于member也不关心验证。所以我使用了这样的更改。
Group.findOneAndUpdate({groupName: groupName}, {
$addToSet: {
member: userRef,
}
},{
lean: true,
select: 'groupName',
}, callback);
就是说直接使用Model.findOneAndUpdate跳过Mongoose的验证,并且查询时避开member这个大数组。