我需要查询大量文件(> 100M),并且我要批量申请5000份文件(每份约4-5MB)。
出于某种原因,第一个请求(没有_id
过滤)快速返回(~1.5s)而
休息需要很长时间(约8-9.5秒)。
现在,当批量阅读500份文件(每份约500kB)时,时间明显更好(~0.5-0.8s),并且对于每个请求都是一致的。
我使用_id + limit
分页方法,因为我看到skip + limit
方法执行得更糟。
这是我的流程示例。
var mongodb = require("mongodb")
var bytes = require("bytes")
...
var filter = {
'_id': { '$gt': this._lastId }
}
if(mongodb.ObjectId.isValid(this._lastId)) {
filter['_id'] = { '$gt': this._lastId }
}
var cursor = this.conn.collection(collectionName)
.find(filter)
.limit(5000)
var start = new Date().getTime()
cursor.toArray(function(err, docs) {
if (err) { ... }
var elapsed = (new Date().getTime() - start) / 1000
console.log(
"Docs:", docs.length,
"Size:", bytes(sizeof(docs)),
"Took:", elapsed + " seconds"
)
var lastDoc = docs[docs.length - 1]
this._lastId = lastDoc._id
})
...
答案 0 :(得分:1)
我发现问题很有趣,试图重现它并得出相同的结果:从id 0到5000的第一次调用很快,而其他所有调用都持续时间更长(大约7x)
这与没有过滤器的阅读有关。如果你在mongo shell中运行你的命令并对你的查找做一个解释,你会发现当从0到5000读取时没有应用过滤器。
您可以使用.batchSize()一次获取更多文档(根据您的数字,每个文档大约1KB)。每个游标迭代的默认值为20。 当您运行.toArray()函数时,它将从MongoDB向您的应用程序发送20KB的块,直到传输5000个文档。使用更大的批次可能会更优化,你应该尝试不同的值,但我会从500开始一次获得500KB,因为它减少了小块的网络开销。 您可能还会发现cursor.forEach()在处理数据时会更好地工作(通过batchSize(n)的块)。在这种情况下,如果您查询整个集合或5000块,如果最后要检查所有文档,则无关紧要。
游标保持连接打开并在MongoDB服务器上分配资源,直到您关闭游标或与数据库的连接,但光标的大小不会增加它只保存批处理数据。
另一方面,我认为做小批量的速度并不快:每个文档的时间相似,文档少10倍,速度快10倍。