将测试数据插入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
Run Code Online (Sandbox Code Playgroud)
用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
Run Code Online (Sandbox Code Playgroud)
这要慢得多.那么,为什么新版本存在这样的差异,我该如何解决呢?
Ada*_*ord 14
在2.6之前,交互式shell将运行循环并仅检查循环中最后一个操作的成功(使用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
Run Code Online (Sandbox Code Playgroud)
现在回到基本相同的性能,仅超过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" : [ ]
})
Run Code Online (Sandbox Code Playgroud)
现在我们在进行批量插入时得到了一个很好的结果文档,而不是仅检查最后的操作(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" : [ ]
})
Run Code Online (Sandbox Code Playgroud)
现在我们可以看到有多少是成功的,哪一个失败了(以及为什么).设置可能有点复杂,但总的来说我认为这是一个改进.
综上所述,以及概述的新首选方式,有一种方法可以将shell强制恢复到传统模式.这是有道理的,因为2.6 shell可能必须连接到旧服务器并与之配合使用.如果您连接到2.4服务器,这将为您处理,但为了强制执行特定连接,您可以运行:
db.getMongo().forceWriteMode("legacy");
Run Code Online (Sandbox Code Playgroud)
完成后,您可以使用以下命令恢复到2.6版本:
db1.getMongo().forceWriteMode("commands");
Run Code Online (Sandbox Code Playgroud)
有关实际用法,请参阅我的crud.js代码段.这在目前有效,但可能会在未来的任何时候被删除,恕不另行通知,并且实际上并不打算广泛使用,因此使用风险自负.
归档时间: |
|
查看次数: |
1558 次 |
最近记录: |