【问题标题】:Why are MongoDB upserts so much slower than inserts (with a unique index)?为什么 MongoDB upserts 比 inserts 慢得多(具有唯一索引)?
【发布时间】:2017-04-07 03:58:36
【问题描述】:

我一直在测试 MongoDB 的限制,看看它是否适用于即将到来的项目,我注意到与插入相比,upsert 相当慢。

当然,我希望它们会更慢,但不会(几乎)慢一个数量级(7400 对 55000 操作/秒)。这是我使用的(nodejs 原生驱动程序)基准测试代码:

(async function() {

  let db = await require('mongodb').MongoClient.connect('mongodb://localhost:27017/mongo-benchmark-8764824692947');
  db.collection('text').createIndex({text:1},{unique:true})

  let batch = db.collection('text').initializeOrderedBulkOp();
  let totalOpCount = 0;
  let batchOpCount = 0;
  let start = Date.now();
  while(1) {

    totalOpCount++;
    batchOpCount++;
    if(batchOpCount === 1000) { // batch 1000 ops at a time
      await batch.execute();
      batch = db.collection('text').initializeOrderedBulkOp();
      batchOpCount = 0;
      let secondsElapsed = (Date.now() - start)/1000;
      console.log(`(${Math.round(totalOpCount/secondsElapsed)} ops per sec) (${totalOpCount} total ops)`)
    }

    /////////  INSERT TEST  ///////// (~55000 ops/sec)
    // batch.insert({text:totalOpCount});

    /////////  UPSERT TEST  ///////// (~7400 ops/sec)
    let text = Math.floor(Math.random()*1000000);
    batch.find({text}).upsert().updateOne({$setOnInsert:{text}});

    if(totalOpCount > 500000) {
      console.log("<< finished >>");
      await db.dropCollection('text');
      db.close();
      break;
    }

  }

})();

您可以通过将其粘贴到index.js,运行npm init -ynpm install --save mongodb 然后node . 来轻松运行它

当我们upsert 一个文档时,mongo 引擎必须检查是否存在与它匹配的现有文档。这可能解释了一些减速,但是唯一索引上的insert 命令不需要相同的碰撞检查吗?谢谢!

编辑:原来需要$setOnInsert 否则我们会得到重复的键错误。

【问题讨论】:

  • 在插入文档时,确实会完成两个主要操作。第一个是查找,第二个是更新/插入。当然你也可以试试unorderedBulkOperation
  • insert 是否也需要 find,因为它是唯一索引(即防止重复键)?还是insert 使用的其他魔法?啊感谢unordering 批处理操作的提示。奇怪的是,它几乎不影响我上面发布的代码的性能,但它确实使我正在使用的其他代码的性能翻了一番!
  • 有趣,看起来text 字段上的索引在这里无效。您可以评论await db.dropCollection('text'); 并尝试在手册upsert 上进行解释吗?这可能会提供一些见解。我擅长nodejs,所以无法运行您的代码。但是,从本质上讲,它看起来像是数据库问题,而不是应用程序问题。我会在本地跑,然后告诉你结果。
  • 更新中的语法看起来不正确:{$set:{text}}。不应该是{$set:{"text" : text}}吗?
  • @VinceBowdren 哦,这是 JavaScript ES6 的简写,抱歉 {$set:{text}} === {$set:{text:text}} === {$set:{"text":text}} (explanation)。 @harshavmb,我不太确定您的意思,抱歉-.explain() 是如何进行批量操作的?我试过并得到了batch.execute(...).explain is not a function

标签: node.js mongodb performance


【解决方案1】:

我通过将 if(batchOpCount === 1000) 更改为 if(batchOpCount === 50000) 使每个批次更大,insert 获得 ~90000 ops/sec 和 ~35000 ops/sec upsert。我不确定为什么批量大小会产生相对差异。较小的批次会导致更少的操作/秒(通信开销)是有道理的,但我不确定为什么 upsertsinserts 遭受更多的痛苦,尽管这可能是一个单独问题的主题。

这个(大约)3 倍的速度差异肯定更接近我所期望的两个操作之间的性能差异,但看起来upserts 仍然比它们应该的慢一点,因为插入必须还检查冲突(由于唯一索引)。这实际上只是一个一半的答案,所以我将保留这个问题,希望 mongo pro 能够出现并提供更完整的答案。

【讨论】:

    猜你喜欢
    • 2015-10-23
    • 2016-12-15
    • 1970-01-01
    • 2017-12-26
    • 2011-01-25
    • 2012-12-20
    • 1970-01-01
    • 1970-01-01
    • 2017-05-10
    相关资源
    最近更新 更多