MongoDB - 更新集合中所有记录的最快方法是什么?

时间:2010-11-10 16:09:09

标签: javascript performance mongodb

我有一个包含900万条记录的集合。我目前正在使用以下脚本来更新整个集合:

simple_update.js

db.mydata.find().forEach(function(data) {
  db.mydata.update({_id:data._id},{$set:{pid:(2571 - data.Y + (data.X * 2572))}});
});

这是从命令行运行,如下所示:

mongo my_test simple_update.js

所以我所做的就是根据简单的计算添加一个新字段 pid

有更快的方法吗?这需要很长时间。

5 个答案:

答案 0 :(得分:28)

你可以做两件事。

  1. 发送'multi'标志设置为true的更新。
  2. 存储功能服务器端并尝试使用server-side code execution
  3. 该链接还包含以下建议:

      

    这是执行批量管理工作的好方法。在服务器上运行mongo,通过localhost接口连接。然后连接非常快且低延迟。这比db.eval()更友好,因为db.eval()会阻止其他操作。

    这可能是你得到的最快的。您必须意识到在单个服务器上发布9M更新将是一项繁重的操作。让我们说你可以获得3k更新/秒,你还在谈论跑步近一个小时。

    这不是真正的“mongo问题”,这将是硬件限制。

答案 1 :(得分:18)

我使用的是:db.collection.update method

// db.collection.update( criteria, objNew, upsert, multi ) // --> for reference
db.collection.update( { "_id" : { $exists : true } }, objNew, upsert, true);

答案 2 :(得分:3)

我不建议将{multi:true}用于更大的数据集,因为它的配置较少。

使用批量插入的更好方法。

批量操作对调度程序任务非常有用。假设您必须删除每天6个月以前的数据。使用批量操作。它速度快,不会减慢服务器速度。当您插入,删除或更新超过十亿个文档时,CPU,内存使用情况不明显。当你处理数百万个文档时,我发现{multi:true}会减慢服务器的速度(需要更多的研究。)

请参阅下面的示例。它是一个js shell脚本,也可以在服务器中作为节点程序运行。(使用npm模块shelljs或类似的实现此目的)

将mongo更新为3.2 +

更新多个唯一文档的常规方法是

let counter = 0;
db.myCol.find({}).sort({$natural:1}).limit(1000000).forEach(function(document){
    counter++;
    document.test_value = "just testing" + counter
    db.myCol.save(document)
});

我尝试时花了310-315秒。更新一百万份文件的时间超过5分钟。

我的收藏品包含1亿多个文件,因此其他人的速度可能不同。

同样使用批量插入

    let counter = 0;
// magic no.- depends on your hardware and document size. - my document size is around 1.5kb-2kb
// performance reduces when this limit is not in 1500-2500 range.
// try different range and find fastest bulk limit for your document size or take an average.
let limitNo = 2222; 
let bulk = db.myCol.initializeUnorderedBulkOp();
let noOfDocsToProcess = 1000000;
db.myCol.find({}).sort({$natural:1}).limit(noOfDocsToProcess).forEach(function(document){
    counter++;
    noOfDocsToProcess --;
    limitNo--;
    bulk.find({_id:document._id}).update({$set:{test_value : "just testing .. " + counter}});
    if(limitNo === 0 || noOfDocsToProcess === 0){
        bulk.execute();
        bulk = db.myCol.initializeUnorderedBulkOp();
        limitNo = 2222;
    }
});

最佳时间是8972毫安。所以平均而言,更新一百万份文件只花了10秒钟。比旧路快30倍。

将代码放在.js文件中,并以mongo shell脚本执行。

如果有人找到更好的方法,请更新。让我们以更快的方式使用mongo。

答案 3 :(得分:0)

不确定它是否会更快,但您可以进行多次更新。只需说update where _id > 0(对于每个对象都是如此)然后将'multi'标志设置为true,它应该做同样的事情,而不必迭代整个集合。

检查一下: MongoDB - Server Side Code Execution

答案 4 :(得分:0)

Mongo 4.2db.collection.update()开始可以接受聚合管道,最终允许基于另一个字段来更新/创建一个字段;从而使我们可以完全在服务器端应用这种查询:

// { Y: 456,  X: 3 }
// { Y: 3452, X: 2 }
db.collection.update(
  {},
  [{ $set: { pid: {
    $sum: [ 2571, { $multiply: [ -1, "$Y" ] }, { $multiply: [ 2572, "$X" ] } ]
  }}}],
  { multi: true }
)
// { Y: 456,  X: 3, pid: 9831 }
// { Y: 3452, X: 2, pid: 4263 }
  • 第一部分{}是匹配查询,用于过滤要更新的文档(在这种情况下为所有文档)。

  • 第二部分[{ $set: { pid: ... } }]是更新聚合管道(请注意方括号表示使用聚合管道)。 $set是新的聚合运算符,别名为$addFields。请注意如何基于同一文档中的pidX)和$XY)的值直接创建$Y

    < / li>
  • 不要忘记{ multi: true },否则只会更新第一个匹配的文档。