将Meteor中的值插入MongoDB非常慢

时间:2016-11-18 11:58:09

标签: node.js mongodb performance meteor

将Meteor中的值插入MongoDB的速度令人难以置信,机器没有任何负载。

  • 系统:Mac OS El Capitan
  • MongoDB版本:2.6.12 (更新为3.2)
  • 流星:1.4.2.3

我从db获取一个值并删除_id以生成一个新值并将该值再次插入到db中。

Meteor.methods({
  testInsert() {
    const id = ID.find({ Project: Number(287), ID: Number(169372), Deleted: false }).fetch();

    if (id === undefined || id === '' || id.length > 1 || id.length === 0) {
      throw new Meteor.Error('no unique id found');
    }

    console.log('got ID ' + id[0].ID);

    const oldId = id[0]._id;
    delete id[0]._id;

    try {
      console.log('Start inserting ... ' + new Date());
      ID.insert(id[0]);
      console.log('Done inserting ' + new Date());
    } catch (e) {
      throw new Meteor.Error('error inserting`);
    }
    console.log('Done single');
  },
});

结果:

  

得到ID 169372

     

开始插入... 2016年11月18日星期五12:25:59 GMT + 0100(CET)

     

完成插入2016年11月18日星期五12:26:09 GMT + 0100(CET)

插入需要10秒钟!我插入的JSON是14kb大或相当小。插入在mongo的shell(命令行)中不到一秒钟。这段代码过去足够快。我桌上也有一个索引。

ID._ensureIndex({ Deleted: 1, ID: 1 });

要明确的是,目前任何插入都很慢,而不仅仅基于上面的示例代码。但奇怪的是,对于一个简单的插入,节点/流星运行的机器上的负载达到100%!有什么想法吗?

更新

MongoDB不是在我的本地开发人员计算机上运行,​​而是在专用数据库服务器上,我使用隧道(如果你想知道为什么错误消息称为localhost :))

更新2:

当我使用for循环插入10个ID流星崩溃时,虽然流星恢复它需要5-10分钟,但它实际上写了所有数据

Exception while polling query {"collectionName":"id","selector":{"id":287,"Deleted":false},"options":{"transform":null}}: MongoError: connection 7 to localhost:27017 timed out

更新3:

我将MongoDB更新为3.2但仍然有例外。

Exception while polling query {"collectionName":"ID","selector":{"ID":287,"Deleted":false},"options":{"transform":null}}: MongoError: connection 17 to localhost:27017 timed out

更新4:

轮询错误/超时与我认为的问题无关,这就是我删除堆栈跟踪的原因。我能够构建一个通用的测试用例来复制这个问题。似乎mongo节点/流星驱动程序无法很好地处理数组属性。我已将带有Java驱动程序的条目插入到mongo中,没有任何问题。我创建了一个测试用例,用500个随机条目填充数组。这个插入语句大约需要10秒钟。通过增加ID的数量,您还将遇到超时错误。

Meteor.methods({
  testInsert() {
    const testIDs = [
      { ID: 100000, array: [] },
      { ID: 200000, array: [] }];

	  function makeTestCase(id) {
	    for (let i = 0; i < 500; i += 1) {
	      id.array.push({
	        "Date": new Date,
	        "Text1" : "Lorem ipsum dolor sit amet, consectetur adipisicing elit.",
	        "Text2" : "Lorem ipsum dolor sit amet, consectetur adipisicing elit.",
	        "Text3" : "Lorem ipsum dolor sit amet, consectetur adipisicing elit.",
	        "Text4" : i,
	        "Text5" : i,
	        "Text6" : i,
	        "Text7" : i,
	      });
	    }
	  }

    testIDs.forEach(makeTestCase);

    function insertID(id) {
      try {
        console.log(`Start inserting ... ${new Date()}`);
        BshID.insert(id, { validate: false });
        console.log(`Done inserting ${new Date()}`);
      } catch (e) {
        throw new Meteor.Error('ID ERROR');
      }
    }

    testIDs.forEach(insertID);

    console.log('all done');
	}
});

1 个答案:

答案 0 :(得分:0)

您可以做一些改进:

ID字段

创建降序索引

如果我正确理解了您的代码,您始终会搜索最旧的记录来生成新文档。如果您创建降序索引,MongoDB会更快地找到您的文档,因为它会优化您的索引以首先查看ID的最高值。 另外,如果您始终按ProjectID进行搜索,则还应在索引中包含Project

首先,删除最旧的索引: ID._dropIndex({Deleted: 1, ID: 1})

然后,创建新索引:ID._ensureIndex({Deleted: 1, ID: -1, Project: -1})

使用findOne而不是find

如果您只需要一个文档,请使用findOne查找此文档,MongoDB无需查看所有记录即可获取结果。此外,您可以将fields属性添加到findOne,只告诉Meteor在此操作中与您相关的字段,但是看到您的示例,您正在创建文档的副本,所以情况并非如此。

ID.findOne({ 
  Project: Number(287), 
  ID: Number(169372), 
  Deleted: false 
});

额外:将MongoDB更新为3.2

您正在使用Meteor 1.4,因此您应该将MongoDB更新为与此Meteor版本兼容的相应版本。查看http://info.meteor.com/blog/announcing-meteor-1.4了解详情。

进一步阅读