如何高效地遍历 MongoDB 超大集合?

原创 Fundebug 随笔 后端 65阅读 2019-03-21 09:10:27 举报

本文使用的编程语言是 Node.js,连接 MongoDB 的模块用的是mongoose。但是,本文介绍的方法适用于其他编程语言及其对应的 MongoDB 模块。

错误方法:find()

也许,在遍历 MongoDB 集合时,我们会这样写:

注意,我们使用的是 Bluebird 的mapSeries而非map,members 数组中的元素是一个一个处理的。这样就够了吗?

当 Member 集合中的 document 不多时,比如只有 1000 个时,那确实没有问题。但是当 Member 集合中有 1000 万个 document 时,会发生什么呢?如下:

可知,内存不足了。

打印find()返回的 members 数组可知,集合中所有元素都返回了,哪个数组放得下 1000 万个 Object?

正确方法:find().cursor()与 eachAsync()

将整个集合 find()全部返回,这种操作应该避免,正确的方法应该是这样的:

使用cursor()方法返回 QueryCursor,然后再使用eachAsync()就可以遍历整个集合了,而且不用担心内存不够。

QueryCursor是什么呢?不妨看一下 mongoose 文档:

A QueryCursor is a concurrency primitive for processing query results one document at a time. A QueryCursor fulfills the Node.js streams3 API, in addition to several other mechanisms for loading documents from MongoDB one at a time.

总之,QueryCursor 可以每次从 MongoDB 中取一个 document,这样显然极大地减少了内存使用。

如何测试?

这篇博客介绍的内容很简单,但是也很容易被忽视。如果大家测试一下,印象会更加深刻一些。

测试代码很简单,大家可以查看Fundebug/loop-mongodb-big-collection

我的测试环境是这样的:

  • ubuntu 14.04
  • mongodb 3.2
  • nodejs 10.9.0

1. 使用 Docker 运行 MongoDB

2. 使用mgodatagen生成测试数据

使用 mgodatagen,1000 万个 document 可以在 1 分多钟生成!

下载 mgodatagen:https://github.com/feliixx/mgodatagen/releases/download/0.7.3/mgodatagen_linux_x86_64.tar.gz

解压之后,复制到/usr/local/bin 目录即可:

mgodatagen 的配置文件mgodatagen-config.json如下:

执行mgodatagen -f mgodatagen-config.json命令,即可生成 10000 万测试数据。

查看 MongoDB,可知新生成的数据有 0.69GB,其实很小,但是使用 find()方法遍历会报错。

3. 执行测试代码

两种不同遍历方法的代码分别位于test1.jstest2.js

参考

关于Fundebug

Fundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了10亿+错误事件,付费客户有Google、360、金山软件、百姓网等众多品牌企业。欢迎大家免费试用

版权声明

转载时请注明作者Fundebug以及本文地址:
https://blog.fundebug.com/2019/03/21/how-to-visit-all-documents-in-a-big-collection-of-mongodb/

评论 ( 0 )
最新评论
暂无评论

赶紧努力消灭 0 回复