Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/395.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript MongoDB-更新集合中所有记录的最快方法是什么?_Javascript_Performance_Mongodb - Fatal编程技术网

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

Javascript MongoDB-更新集合中所有记录的最快方法是什么?,javascript,performance,mongodb,Javascript,Performance,Mongodb,我收集了900万张唱片。我当前正在使用以下脚本更新整个集合: simple_update.js 这将从命令行运行,如下所示: mongo my_test simple_update.js 所以我所做的就是在一个简单的计算基础上添加一个新的字段pid 有没有更快的办法?这需要大量的时间。不确定是否会更快,但您可以进行多次更新。只需说updatewhere _id>0(对于每个对象都是如此),然后将“multi”标志设置为true,它应该执行相同的操作,而不必遍历整个集合 看看这个: 你可以做两件

我收集了900万张唱片。我当前正在使用以下脚本更新整个集合:

simple_update.js

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

mongo my_test simple_update.js
所以我所做的就是在一个简单的计算基础上添加一个新的字段pid


有没有更快的办法?这需要大量的时间。

不确定是否会更快,但您可以进行多次更新。只需说
updatewhere _id>0
(对于每个对象都是如此),然后将“multi”标志设置为true,它应该执行相同的操作,而不必遍历整个集合

看看这个:
你可以做两件事

  • 发送“multi”标志设置为true的更新
  • 将函数存储在服务器端并尝试使用
  • 该链接还包含以下建议:

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

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

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

    我使用的是:


    我不建议对较大的数据集使用{multi:true},因为它的可配置性较差

    使用批量插入的更好方法

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

    见下面的示例。这是一个js外壳脚本,也可以在服务器上作为节点程序运行。(使用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文件中,并作为mongoshell脚本执行


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

    启动
    mongo 4.2
    ,可以接受聚合管道,最终允许基于另一个字段更新/创建字段;从而使我们能够在服务器端完全应用这种查询:

    // { 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 }
    
    • 第一部分是匹配查询,过滤要更新的文档(本例中的所有文档)

    • 第二部分是更新聚合管道(注意方括号表示使用聚合管道)。是一个新的聚合运算符,别名为
      $addFields
      。请注意,如何根据同一文档中的
      X
      $X
      )和
      Y
      $Y
      )的值直接创建
      pid

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


    那么拥有多个实例(从/主)是否会加快速度?主/从不会缩短写入时间。Mongo只有一个写线程,在进行这样的大规模更新时,它通常受到磁盘吞吐量的限制。您需要的“多个实例”是切分。使用分片,您将拥有两台具有两个独立磁盘的机器,并且您将获得几乎两倍的写入吞吐量。不过,请再次查看您的硬件,并将其与您的预期吞吐量进行比较。好的。我明白。读书怎么样?切分也是一种加速阅读或查询的方法吗?拥有良好阅读时间的最佳方法是将所有内容都保存在内存中。这意味着拥有尽可能多的可用RAM。切分是“添加更多RAM”的合理方式,因为您可以使用多台机器的RAM。从这个意义上说,切分是“更快的”。如果您查看原始查询,它的编写方式是,每个文档都必须通过连接到客户端。因此,在服务器上通过直接连接运行它意味着您不必通过写操作发送数据。显然,使用“多重更新”是最简单的。但是,对于9M项,我可能会编写一个批处理脚本,以便跟踪进度。使用null将抛出一个错误。这在API中是不一致的,因为其他方法接受null作为搜索条件(并将其解释为“匹配任何”),例如find和findOne函数。在shell中,“let”不能全局使用。可以在函数中使用。因此,请使用“var”而不是“let”。
        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;
        }
    });
    
    // { 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 }