对大型mongo集合的部分doc更新 - 如何不锁定数据库?

时间:2013-12-21 14:27:22

标签: mongodb

我有一个mongo数据库实例,其中有一个集合,其中有大约1700万条记录。

我希望改变所有1700万个文档的文档结构(在文档中添加新属性),这样我就不必有问题地处理不同的结构以及使查询更容易编写。

我被告知,如果我运行更新脚本来执行此操作,它将锁定整个数据库,可能会删除我们的网站。

如果不发生这种情况,更改文档的最简单方法是什么? (我不介意更新是否会缓慢发生,只要它最终发生)

我试图做的查询是:

db.history.update(
  { type : { $exists: false }},
  {
    $set: { type: 'PROGRAM' }
  },
  { multi: true } 
)

2 个答案:

答案 0 :(得分:3)

您可以批量更新集合(每批50万),这将分配负载。

我创建了一个包含20000000条记录的集合,并在其上运行查询。在虚拟机上更新花了大约3分钟,我仍然可以在单独的控制台中读取数据库。

> for(var i=0;i<20000000;i++){db.testcoll.insert({"somefield":i});}

mongo中的锁定非常轻量级,并且在整个更新期间不会被保留。可以把它想象成20000000个单独的更新。你可以在这里阅读更多内容:

http://docs.mongodb.org/manual/faq/concurrency/

答案 1 :(得分:1)

实际上在乎你的更新查询是否很慢,因为你知道的数据库上的写锁定问题,两者都是紧密相连的。这里不是一个简单的读取查询,你真的希望这个写入查询尽可能快。

更新“查找”部分是此处的关键部分。首先,由于您的集合包含数百万个文档,因此最好保持字段名称大小尽可能小(理想情况下是单个字符:type =&gt; t)。这有助于因为mongodb集合的无模式特性。

其次,更重要的是,您需要使查询使用正确的索引。为此,您需要解决未经优化的 $ exists 运算符(实际上有几种方法可以实现)。

第三,您可以自己处理字段值。使用http://bsonspec.org/#/specification估计要存储的值的大小,并最终选择一个更好的选择(在您的情况下,您可以用数字常量替换'PROGRAM'字符串,例如,获取一些字节进程,乘以每个更新多个查询更新的文档数)。您要写入的数据越小,操作就越快。

可以激发你的其他问题的一些链接:

Can MongoDB use an index when checking for existence of a field with $exists operator?

Improve querying fields exist in MongoDB