将测试数据插入MongoDB时,我通常只使用for
循环来执行大量的单次插入操作。在2.4及以下版本中,这非常快(〜2秒),例如:
> db.timecheck.drop();
true
> start = new Date(); for(var i = 0; i < 100000; i++){db.timecheck.insert({"_id" : i})}; end = new Date(); print(end - start);
2246
在2.6上尝试相同的操作明显较慢(〜37秒):
> db.timecheck.drop();
true
> start = new Date(); for(var i = 0; i < 100000; i++){db.timecheck.insert({"_id" : i})}; end = new Date(); print(end - start);
37169
那要慢得多。那么,为什么新版本有这么大的差异,我该如何解决呢?
在2.6之前,交互式外壳程序将在循环中运行,并且仅检查循环中最后一个操作的成功(使用getLastError)(更具体地说,它在每次回车后都调用getLastError,最后一个操作是循环中的最后一个插入) 。在2.6版本中,Shell现在将检查循环中每个单独操作的状态。从本质上讲,这意味着2.6的“慢”可归因于已确认的写入性能与未确认的写入性能,而不是实际的性能问题。
一段时间以来,确认的写入已成为默认的写入方式,因此我认为2.6中的行为更为正确,尽管对于习惯于原始行为的我们来说有些不便。
要恢复到以前的性能水平,答案是使用新的无序批量插入API。这是一个定时版本:
> db.timecheck.drop();
true
> var bulk = db.timecheck.initializeUnorderedBulkOp(); start = new Date(); for(var i = 0; i < 100000; i++){bulk.insert({"_id" : i})}; bulk.execute({w:1}); end = new Date(); print(end - start);
2246
现在,仅用2秒多的时间就恢复了基本相同的性能。当然,它有点笨重(请双关语),但是您确切知道自己所得到的东西,我认为总体上来说这是一件好事。当您不寻找时序信息时,这里还有一个好处。让我们摆脱它,然后再次运行插入:
> db.timecheck.drop();
true
> var bulk = db.timecheck.initializeUnorderedBulkOp(); for(var i = 0; i < 100000; i++){bulk.insert({"_id" : i})}; bulk.execute({w:1});
BulkWriteResult({
"writeErrors" : [ ],
"writeConcernErrors" : [ ],
"nInserted" : 100000,
"nUpserted" : 0,
"nMatched" : 0,
"nModified" : 0,
"nRemoved" : 0,
"upserted" : [ ]
})
现在,当我们进行批量插入时,我们得到了一个不错的结果文档,而不是仅检查最后一个操作(2.4版本中的其余所有操作实际上都是发送和忘记了)。由于它是无序的批量操作,因此在遇到错误时将继续执行并报告本文档中的每个此类错误。在上面的示例中看不到任何内容,但是很容易人为地创建故障方案。让我们只是预先插入一个我们知道会出现的值,从而在(默认)唯一_id索引上导致重复的键错误:
> db.timecheck.drop();
true
> db.timecheck.insert({_id : 500})
WriteResult({ "nInserted" : 1 })
> var bulk = db.timecheck.initializeUnorderedBulkOp(); for(var i = 0; i < 100000; i++){bulk.insert({"_id" : i})}; bulk.execute({w:1});
2014-03-28T16:19:40.923+0000 BulkWriteError({
"writeErrors" : [
{
"index" : 500,
"code" : 11000,
"errmsg" : "insertDocument :: caused by :: 11000 E11000 duplicate key error index: test.timecheck.$_id_ dup key: { : 500.0 }",
"op" : {
"_id" : 500
}
}
],
"writeConcernErrors" : [ ],
"nInserted" : 99999,
"nUpserted" : 0,
"nMatched" : 0,
"nModified" : 0,
"nRemoved" : 0,
"upserted" : [ ]
})
现在我们可以看到有多少成功,哪些失败了(为什么)。设置可能会稍微复杂一些,但总的来说,我认为这是一种改进。
综上所述,并概述了新的首选方式,有一种方法可以将Shell强制返回到旧模式。这是有道理的,因为2.6 Shell可能必须连接到较旧的服务器并与之配合使用。如果您连接到2.4服务器,这将为您解决,但是如果要强制进行特定连接,则可以运行:
db.getMongo().forceWriteMode("legacy");
完成后,您可以使用以下方法恢复到2.6版本:
db1.getMongo().forceWriteMode("commands");
有关实际用法,请参阅我的crud.js片段。该功能目前可以使用,但是将来可能会在不通知的情况下将其删除,并且实际上并不打算广泛使用,因此使用后果自负。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句