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

mat*_*ent 38 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))}});
});
Run Code Online (Sandbox Code Playgroud)

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

mongo my_test simple_update.js
Run Code Online (Sandbox Code Playgroud)

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

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

Gat*_* VP 28

你可以做两件事.

  1. 发送"multi"标志设置为true的更新.
  2. 存储功能服务器端并尝试使用服务器端代码执行.

该链接还包含以下建议:

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

这可能是你得到的最快.您必须意识到在单个服务器上发布9M更新将是一项繁重的操作.假设您可以获得3k更新/秒,您仍然在谈论运行近一个小时.

这不是一个"mongo问题",这将是一个硬件限制.


Tel*_*ias 18

我使用的是:db.collection.update方法

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

  • 您还可以使用{}(空BSSON对象)作为第一个参数.使用null将引发错误.这是API中的不一致,因为其他方法接受null作为搜索条件(并将其解释为"匹配任何"),例如find和findOne函数. (6认同)

shi*_*jin 6

我不建议对较大的数据集使用 {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)
});
Run Code Online (Sandbox Code Playgroud)

我尝试时花了 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;
    }
});
Run Code Online (Sandbox Code Playgroud)

最好的时间是 8972 毫秒。因此,更新一百万个文档平均只需要 10 秒。比旧方法快 30 倍。

将代码放入 .js 文件中并作为 mongo shell 脚本执行。

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