MongoDB中执行批操作
2022-12-15 08:43 abce 阅读(733) 评论(0) 编辑 收藏 举报和大多数数据库系统类似,MongoDB也提供了api,支持在单个操作中插入或检索多个文档。
通过减少客户端和MongoDB之间的交互次数,可以提高数据库的性能。
使用.batchsize()优化批量读
当使用游标检索数据,可以使用batchSize来指定每次操作读取的行数。
比如,下面的游标中使用limit限定了处理的所有行数;而arraySize控制了每次网络请求从mongodb中检索的文档数。
1 2 3 4 5 | cursor = useDb.collection( 'millions' ).find().limit(limit).batchSize(arraySize); for (let doc = await cursor . next (); doc != null ; doc = await cursor . next ()) { counter++; } |
batchSize操作符不会真正给程序返回一个数组,只是控制每次网络交互中检索的文档数量。
默认情况下,MongoDB为.batchSize设置了一个相当高的值,如果你随意更改它,可能会很容易降低性能。
但是,如果你从远程表取回大量的小的行,增加该选项的值会显著提升性能。
以下是我们的测试结果,将batchSize设置成小于1000,性能会很糟糕,有时会特别糟糕。设置大于1000后,会有显著的性能提升。
代码中要避免过量的网络交互(Network Round Trips)
batchSize()可以帮助减少网络开销。有时候,唯一可以优化网络来回开销的方法是优化代码逻辑。比如:
1 2 3 4 5 6 7 8 9 10 | for (i = 1; i < max ; i++) { //console.log(i); if ((i % 100) == 0) { cursor = useDb.collection(mycollection).find({ _id: i }); const doc = await cursor . next (); counter++; } } |
我们正在从MongoDB集合中每100个文档中取出一个。如果集合很大,那就是大量的网络往返。此外,这些请求中的每一个都将通过索引查找来满足,并且所有这些索引查找次数是非常多的。
或者,我们可以在一个操作中提取整个集合,然后提取我们想要的文档。
1 2 3 4 5 6 | const cursor = useDb.collection(mycollection).find().batchSize(10000); for (let doc = await cursor . next (); doc != null ; doc = await cursor . next ()) { if (doc._id % divisor === 0) { counter++; } } |
直觉上,可能会认为第二种方法会花费更长的时间。毕竟,我们现在从MongoDB中检索的文档多了100倍,对吧?但是,由于游标在每个批处理中(在底层)要拉过数千个文档,因此第二种方法实际上网络强度要小得多。如果数据库位于一个较慢的网络上,那么第二种方法将会快得多。
下面我们将看到本地服务器(例如,在我的笔记本电脑上)和远程服务器(Altas)两种方法的性能。
当数据在我的笔记本电脑上时,第一种方法要快一些。但是当服务器是远程的时,在一次操作中调出所有数据要快得多。
批量插入
就像我们想要批量地从MongoDB中取出数据一样,我们也想批量地插入数据——如果我们有很多数据要插入的话。批量插入的代码比find()示例要复杂一些。下面是一个批量插入数据的示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | if (orderedFlag == 1) bulk = db.bulkTest.initializeOrderedBulkOp(); else bulk = db.bulkTest.initializeUnorderedBulkOp(); for (i = 1; i <= NumberOfDocuments; i++) { // Insert a row into the bulk batch var doc = { _id: i, i: i, zz: zz }; bulk. insert (doc); // Execute the batch if batchsize reached if (i % batchSize == 0) { bulk. execute (); if (orderedFlag == 1) bulk = db.bulkTest.initializeOrderedBulkOp(); else bulk = db.bulkTest.initializeUnorderedBulkOp(); } } bulk. execute (); |
在第2行或第4行,我们为bulkTest集合初始化一个bulk对象。有两种方法可以做到这一点——我们可以创建有序的或非有序的。Ordered保证集合按照它们呈现给bulk对象的顺序被插入。否则,MongoDB可以优化插入到多个流,这些流可能不是按顺序插入的。
在第9行,我们将文档添加到"bulk"对象。当达到适当的批处理大小(第11行)时,执行批处理(第12行)并重新初始化bulk对象(第14或16行)。我们在最后(第19行)进一步执行,以确保插入了所有文档。
我使用不同的"批处理"大小(例如,在execute()调用之间插入的文档数量)将100,000个文档插入到我笔记本电脑上的一个集合中。我尝试了有序和无序的批量操作。结果如下图所示:
结果非常明显——批量插入可以显著提高性能。最初,批处理大小的每一次增加都会降低性能,但最终性能会趋于稳定。
我相信MongoDB无论如何都将每个操作的批数限制在1000个,但在此之前,你的网络数据包也有可能被填满,并且你不会看到通过增加批大小可以减少运行时间。因为文档大小不同,可能网络包已经满了。
https://dzone.com/articles/bulk-operations-in-mongodb
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
2016-12-15 ebs r12 -- adadmin: error while loading shared libraries: libclntsh.so.10.1
2016-12-15 ebs R12.2启动报错"failed to start a managed process after the maximum retry limit"
2016-12-15 通过数据库查看EBS的登录地址
2015-12-15 MySQL加载配置文件的顺序